CVE-2026-5229

Receive Notifications After Form Submitting – Form Notify for Any Forms <= 1.1.10 - Unauthenticated Authentication Bypass via LINE OAuth Callback

criticalImproper Authentication
9.8
CVSS Score
9.8
CVSS Score
critical
Severity
1.1.11
Patched in
1d
Time to patch

Description

The Form Notify plugin for WordPress is vulnerable to Authentication Bypass in versions up to and including 1.1.10. This is due to the plugin trusting user-controlled cookie data to determine which WordPress account to authenticate after a LINE OAuth login. When LINE doesn't provide an email address (which is common), the plugin falls back to reading the 'form_notify_line_email' cookie value without verifying that the LINE account is associated with that email address. This makes it possible for unauthenticated attackers to gain access to any user account on the site, including administrator accounts, by completing a LINE OAuth flow with their own LINE account while injecting a malicious cookie containing the target victim's email address.

CVSS Vector Breakdown

CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
Attack Vector
Network
Attack Complexity
Low
Privileges Required
None
User Interaction
None
Scope
Unchanged
High
Confidentiality
High
Integrity
High
Availability

Technical Details

Affected versions<=1.1.10
PublishedMay 14, 2026
Last updatedMay 15, 2026
Affected pluginform-notify

What Changed in the Fix

Changes introduced in v1.1.11

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

# Exploitation Research Plan: CVE-2026-5229 (Form Notify Authentication Bypass) ## 1. Vulnerability Summary The **Receive Notifications After Form Submitting – Form Notify for Any Forms** plugin (version <= 1.1.10) is vulnerable to an unauthenticated authentication bypass. The vulnerability resides…

Show full research plan

Exploitation Research Plan: CVE-2026-5229 (Form Notify Authentication Bypass)

1. Vulnerability Summary

The Receive Notifications After Form Submitting – Form Notify for Any Forms plugin (version <= 1.1.10) is vulnerable to an unauthenticated authentication bypass. The vulnerability resides in the LINE OAuth callback logic. Specifically, when a user authenticates via LINE but does not provide an email address (e.g., they denied the email scope), the plugin trusts user-controlled data (the form_notify_line_email cookie) to determine which WordPress account to log into.

An attacker can use their own LINE account to satisfy the OAuth signature verification and then provide a target administrator's email in the cookie to gain full administrative access.

2. Attack Vector Analysis

  • Endpoint: /wp-json/form-notify/v1/callback (REST API)
  • Method: GET
  • Preconditions:
    1. The plugin must have LINE Login configured (form_notify_line_login_channel_id and secret set).
    2. An attacker must have a valid LINE account.
    3. The attacker must know the email address of a target administrator.
  • Vulnerable Parameters: form_notify_line_email (Cookie).
  • Authentication: Unauthenticated. The permission_callback for the REST route is __return_true.

3. Code Flow

  1. Entry Point: The attacker initiates the flow by calling GET /wp-json/form-notify/v1/login.
  2. State Generation: Route::get_api_login() (in src/APIs/Line/Login/Route.php) generates a state using md5(time()), stores it in a transient form_notify_line_state_{state}, and redirects the user to LINE.
  3. OAuth Verification: After the attacker authenticates with their LINE account, LINE redirects back to /wp-json/form-notify/v1/callback?code={CODE}&state={STATE}.
  4. Callback Handling: Route::get_api_callback() (in src/APIs/Line/Login/Route.php):
    • Validates that the provided state matches the transient/session.
    • Calls SDK::get_access_token($code) to exchange the code for a token from LINE.
    • Calls SDK::get_line_profile(...) which calls https://api.line.me/oauth2/v2.1/verify to validate the ID Token.
  5. Vulnerable Sink:
    • If LINE does not provide an email ($user->email is empty), the code (in the vulnerable version as described) falls back to reading $_COOKIE['form_notify_line_email'] (Inferred based on description; provided snippet in Route.php line 126 shows a hardcoded fallback $user_raw_id . '@line.com', suggesting the cookie usage was the original implementation or exists in a specific configuration path).
    • The determined $user_email is passed to User::is_member($user_email, ...) and then User::login(...) in src/APIs/Line/Login/User.php.
  6. Authentication Bypass: User::login() calls wp_set_auth_cookie($this->user->ID) for the user found via the malicious email, effectively logging the attacker in as the victim.

4. Nonce Acquisition Strategy

The vulnerable REST routes (form-notify/v1/login and form-notify/v1/callback) do not require a WordPress nonce.

The register_api_route function in src/APIs/Line/Login/Route.php defines the permission_callback as true for both endpoints. These are public OAuth endpoints meant for external redirects.

If a nonce were needed for any reason, the plugin localizes lineLoginButtonParams in form-notify.php:

  • JS Variable: window.lineLoginButtonParams
  • Extraction: browser_eval("window.lineLoginButtonParams.some_key") (though no nonce is registered in the provided wp_localize_script call).

5. Exploitation Strategy

Step 1: Initialize Session and State

Call the login endpoint to populate the transient on the server.

  • Request: GET /wp-json/form-notify/v1/login
  • Tool: http_request
  • Objective: Follow the redirect to capture the state parameter generated by the plugin.

Step 2: Prepare Mock LINE Responses (Local Test Environment)

Because the PoC environment cannot connect to real LINE APIs, the agent must intercept the wp_remote_request calls made by SDK.php to api.line.me.

  • Mock Token Response: Return a valid-looking access_token and id_token.
  • Mock Verify Response: Return a JSON object where sub is the attacker's LINE ID, but email is omitted.

Step 3: Execute Callback with Malicious Cookie

Send the callback request with the valid state and the target administrator's email in the cookie.

  • URL: /wp-json/form-notify/v1/callback?code=mock_code&state={STATE_FROM_STEP_1}
  • Method: GET
  • Cookie Header: form_notify_line_email=admin@example.com
  • Tool: http_request

Step 4: Capture Auth Cookies

The response to Step 3 should include Set-Cookie headers for wordpress_logged_in_....

6. Test Data Setup

  1. Target User: Ensure an administrator exists with email admin@example.com.
    • wp user create attacker attacker@example.com --role=administrator (or use existing).
  2. Plugin Configuration: The plugin needs a dummy Channel ID to enable the routes.
    • wp option update form_notify_line_login_channel_id "123456"
    • wp option update form_notify_line_login_channel_secret "secret"

7. Expected Results

  • The request to /wp-json/form-notify/v1/callback should result in a 302 Redirect (likely to the admin dashboard or the URL stored in login_redirect_url).
  • The response headers should contain a valid WordPress authentication cookie (wordpress_logged_in_...) for the administrator account.

8. Verification Steps

  1. Identify the session: Capture the wordpress_logged_in cookie from the exploit response.
  2. Verify Identity: Use the captured cookie to make a request to /wp-json/wp/v2/users/me.
    • Expected: The response JSON should show slug: "admin" and capabilities: { administrator: true }.
  3. Database Check: Verify the form_notify_line_user_id meta was added to the admin user.
    • wp user meta get 1 form_notify_line_user_id

9. Alternative Approaches

If the form_notify_line_email cookie is not the direct injection point:

  • Check lgmode Parameter: The User::set_login_redirect_url function in src/APIs/Line/Login/User.php processes the lgmode parameter and sets a login_redirect_url cookie. Check if this can be used for Open Redirect to steal tokens if the site is configured with other SSO.
  • Sign-Up Flow: If the target email does not exist, the plugin calls User::sign_up(). An attacker could potentially register a new account with arbitrary roles if form_notify_line_btn_user_role is misconfigured.

Check if your site is affected.

Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.