[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"$fa--vugiFITmF3zPnsbV28pcFh5ou1PcAzoo0RwGp298":3},{"id":4,"url_slug":5,"title":6,"description":7,"plugin_slug":8,"theme_slug":9,"affected_versions":10,"patched_in_version":11,"severity":12,"cvss_score":13,"cvss_vector":14,"vuln_type":15,"published_date":16,"updated_date":17,"references":18,"days_to_patch":20,"patch_diff_files":21,"patch_trac_url":9,"research_status":28,"research_verified":29,"research_rounds_completed":30,"research_plan":31,"research_summary":32,"research_vulnerable_code":33,"research_fix_diff":34,"research_exploit_outline":35,"research_model_used":36,"research_started_at":37,"research_completed_at":38,"research_error":9,"poc_status":9,"poc_video_id":9,"poc_summary":9,"poc_steps":9,"poc_tested_at":9,"poc_wp_version":9,"poc_php_version":9,"poc_playwright_script":9,"poc_exploit_code":9,"poc_has_trace":29,"poc_model_used":9,"poc_verification_depth":9,"poc_exploit_code_gated":29,"source_links":39},"CVE-2026-3655","otp-login-with-phone-number-otp-verification-unauthenticated-authentication-bypass-via-firebase-otp-verification","OTP Login With Phone Number, OTP Verification \u003C= 1.8.60 - Unauthenticated Authentication Bypass via Firebase OTP Verification","The OTP Login With Phone Number, OTP Verification plugin for WordPress is vulnerable to authentication bypass in versions 1.8.50 through 1.8.60. This is due to the Firebase verification flow in the `lwp_ajax_register` AJAX handler not binding the Firebase session to the phone number supplied in the request. The `idehweb_lwp_activate_through_firebase()` function validates that a Firebase OTP session is legitimate, but the `phoneNumber` returned by Firebase is never compared against the victim's stored phone number. This makes it possible for unauthenticated attackers to authenticate as any user who has a phone number stored in user meta, including administrators, by verifying their own Firebase session and supplying the victim's phone number in the same request.","login-with-phone-number",null,">=1.8.50 \u003C=1.8.60","1.8.61","critical",9.8,"CVSS:3.1\u002FAV:N\u002FAC:L\u002FPR:N\u002FUI:N\u002FS:U\u002FC:H\u002FI:H\u002FA:H","Improper Authentication","2026-05-28 17:56:28","2026-05-29 06:43:44",[19],"https:\u002F\u002Fwww.wordfence.com\u002Fthreat-intel\u002Fvulnerabilities\u002Fid\u002F7fc410f2-5f2b-4eea-a0fb-fe58f988f95f?source=api-prod",1,[22,23,24,25,26,27],"README.md","inc\u002Fadmin-functions.php","inc\u002Fajax-handlers.php","inc\u002Ffrontend-functions.php","login-with-phonenumber.php","readme.txt","researched",false,3,"This research plan outlines the steps required to demonstrate the unauthenticated authentication bypass vulnerability in the **OTP Login With Phone Number, OTP Verification** plugin for WordPress.\n\n---\n\n### 1. Vulnerability Summary\n*   **ID**: CVE-2026-3655\n*   **Plugin**: OTP Login With Phone Number, OTP Verification (slug: `login-with-phone-number`)\n*   **Affected Versions**: 1.8.50 - 1.8.60\n*   **Vulnerability Type**: Improper Authentication (Logic Flaw)\n*   **Location**: `inc\u002Fajax-handlers.php`, specifically the `lwp_ajax_register` handler and the `idehweb_lwp_activate_through_firebase()` helper function.\n*   **Root Cause**: The plugin uses Firebase for OTP verification. While it correctly verifies the integrity of the Firebase `idToken` (confirming a user successfully passed OTP), it fails to check if the phone number associated with that token matches the `username` (phone number) requested for login. An attacker can provide a valid Firebase token for their own phone number and the phone number of an administrator to log in as the administrator.\n\n### 2. Attack Vector Analysis\n*   **Endpoint**: `\u002Fwp-admin\u002Fadmin-ajax.php`\n*   **Action**: `lwp_ajax_register` (Registered for both `wp_ajax_` and `wp_ajax_nopriv_` in `login-with-phonenumber.php`).\n*   **Authentication**: Unauthenticated.\n*   **Payload Parameters**:\n    *   `action`: `lwp_ajax_register`\n    *   `username`: The victim's phone number (stored in `phone_number` user meta).\n    *   `method`: `firebase`\n    *   `nonce`: A valid WordPress nonce for the action `lwp_login` (extracted from the frontend).\n    *   `idToken`: A valid Firebase Identity Token obtained by the attacker for their own phone number.\n\n### 3. Code Flow\n1.  **Entry Point**: An unauthenticated user sends a request to `admin-ajax.php` with `action=lwp_ajax_register`.\n2.  **Nonce Verification**: The handler verifies the nonce provided in the request (likely using the `lwp_login` action string, as seen in `lwp_ajax_login`).\n3.  **Method Selection**: The handler checks the `method` parameter. If set to `firebase`, it calls `idehweb_lwp_activate_through_firebase($_POST['idToken'])`.\n4.  **Firebase Validation**: `idehweb_lwp_activate_through_firebase` calls the Google Firebase API to verify the token. It receives a response containing the `phoneNumber` verified by Firebase.\n5.  **Logic Flaw**: The handler receives confirmation that a phone number was verified but **does not compare** the verified phone number with the `username` parameter provided in the request.\n6.  **Authentication**: The handler uses the provided `username` (the victim's phone number) to find the user (`$this->phone_number_exist($phone_number)`).\n7.  **Session Creation**: The handler calls `wp_set_auth_cookie()` for the found user (the victim), effectively logging the attacker in as that user.\n\n### 4. Nonce Acquisition Strategy\nThe plugin enqueues its scripts and localizes a nonce on pages where the `[idehweb_lwp]` shortcode is present.\n\n1.  **Identify Localization**: In `inc\u002Ffrontend-functions.php`, the function `enqueue_scripts()` registers the script `idehweb-lwp` and uses `wp_localize_script()` to pass data to JavaScript.\n2.  **JS Variable**: The localized object is named `userspn_ajax`.\n3.  **Nonce Key**: The nonce is stored in `userspn_ajax.nonce`.\n4.  **Strategy**:\n    *   Create a public page containing the shortcode: `wp post create --post_type=page --post_status=publish --post_content='[idehweb_lwp]'`.\n    *   Navigate to this page using the browser tool.\n    *   Extract the nonce using `browser_eval(\"userspn_ajax.nonce\")`.\n\n### 5. Exploitation Strategy\n\n#### Pre-requisites\n*   Firebase must be enabled in the plugin settings (`idehweb_lwp_settings`). This requires a Firebase API Key.\n*   A target user (administrator) must have a phone number in their `phone_number` meta.\n\n#### Steps\n1.  **Obtain Victim Phone Number**: Identify the phone number of the target administrator.\n2.  **Generate Attacker Token**: In a real-world scenario, the attacker would use the Firebase JS SDK on the site's frontend to perform an OTP check on their *own* phone number and capture the `idToken`. For a PoC in a restricted environment, you may need to mock the Firebase API response if the environment cannot reach Google.\n3.  **Construct Payload**:\n    *   `action`: `lwp_ajax_register`\n    *   `username`: `[VICTIM_PHONE_NUMBER]`\n    *   `method`: `firebase`\n    *   `nonce`: `[EXTRACTED_NONCE]`\n    *   `idToken`: `[ATTACKER_VALID_TOKEN]`\n4.  **Send Request**: Use `http_request` to send a POST request to `admin-ajax.php`.\n\n```json\n{\n  \"method\": \"POST\",\n  \"url\": \"http:\u002F\u002Flocalhost:8080\u002Fwp-admin\u002Fadmin-ajax.php\",\n  \"headers\": {\n    \"Content-Type\": \"application\u002Fx-www-form-urlencoded\"\n  },\n  \"params\": {\n    \"action\": \"lwp_ajax_register\",\n    \"username\": \"1234567890\",\n    \"method\": \"firebase\",\n    \"nonce\": \"a1b2c3d4e5\",\n    \"idToken\": \"VALID_FIREBASE_TOKEN_FOR_ATTACKER\"\n  }\n}\n```\n\n### 6. Test Data Setup\n1.  **Create Admin**: `wp user create victim_admin admin@example.com --role=administrator --user_pass=password`\n2.  **Set Phone Number**: `wp user meta set victim_admin phone_number 1234567890`\n3.  **Configure Plugin**: Enable Firebase (requires setting options in `idehweb_lwp_settings` via `wp option update`).\n    *   `idehweb_store_number_with_country_code` = `1`\n    *   `idehweb_default_gateways` = `['firebase']`\n    *   `idehweb_use_custom_gateway` = `1`\n4.  **Create Nonce Page**: `wp post create --post_type=page --post_status=publish --post_title='Login' --post_content='[idehweb_lwp]'`\n\n### 7. Expected Results\n*   The AJAX response should return `success: true`.\n*   The response should contain `Set-Cookie` headers for the target administrator (`wordpress_logged_in_...`).\n*   Subsequent requests to `\u002Fwp-admin\u002F` using the returned cookies should grant administrative access.\n\n### 8. Verification Steps\n1.  **Check Cookies**: Verify the `http_request` response contains authentication cookies.\n2.  **Verify Session**: Use the captured cookies to request `http:\u002F\u002Flocalhost:8080\u002Fwp-admin\u002Findex.php`. If the response contains the WordPress Dashboard, the bypass is successful.\n3.  **Database State**: Check `wp_user_meta` to ensure no changes were made to the admin's phone number (confirming the bypass used the attacker's token without modifying the victim).\n\n### 9. Alternative Approaches\n*   **Different Handler**: Check `lwp_ajax_login` (seen in `inc\u002Fajax-handlers.php`). If it also handles Firebase verification via `idehweb_lwp_activate_through_firebase()`, it may be equally vulnerable.\n*   **Method Spoofing**: If Firebase is not configured, check if other verification methods (like `sms`) also fail to bind the session to the phone number. However, the Firebase flow is specifically called out in the CVE description.","The OTP Login With Phone Number, OTP Verification plugin is vulnerable to a critical authentication bypass via the Firebase OTP flow. Because the plugin fails to verify that the phone number returned by a valid Firebase session matches the phone number requested for authentication, an attacker can use a token for their own phone number to log in as any user (including administrators) who has a phone number stored in their profile.","\u002F\u002F inc\u002Fajax-handlers.php - roughly line 658 (lwp_ajax_register) and 714 (lwp_ajax_login)\n\n\u002F\u002F The code checks if the Firebase response is valid but does not compare the number\n\u002F\u002F contained within the response to the user being requested ($phone_number).\n\n$response = $this->idehweb_lwp_activate_through_firebase($_POST['idToken']);\n\nif (isset($response->error)) {\n    wp_send_json([\n        'success' => false,\n        'message' => $response->error->message\n    ]);\n} else {\n    \u002F\u002F VULNERABILITY: The code proceeds to find and log in the user based on the provided\n    \u002F\u002F request parameters without ensuring the Firebase session was for that specific user.\n    $user = get_user_by('ID', $username_exists);\n    if (!is_wp_error($user)) {\n        wp_set_auth_cookie($user->ID, true);\n        wp_send_json_success();\n    }\n}","--- \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Flogin-with-phone-number\u002F1.8.60\u002Finc\u002Fajax-handlers.php\t2026-02-07 06:44:48.000000000 +0000\n+++ \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Flogin-with-phone-number\u002F1.8.61\u002Finc\u002Fajax-handlers.php\t2026-03-10 17:29:54.000000000 +0000\n@@ -658,6 +658,21 @@\n                     ]);\n                 } else {\n \u002F\u002F                if($response=='true') {\n+\n+                    $firebase_phone = isset($response->phoneNumber) ? ltrim($response->phoneNumber, '+') : '';\n+                    $requested_phone = $phone_number;\n+\n+                    if (empty($firebase_phone) || (\n+                            $firebase_phone !== $requested_phone &&\n+                            !str_ends_with($firebase_phone, $requested_phone)\n+                        )) {\n+                        wp_send_json([\n+                            'success' => false,\n+                            'message' => __('Phone number mismatch. Verification failed.', 'login-with-phone-number')\n+                        ]);\n+                    }\n+\n+\n                     $user = get_user_by('ID', $username_exists);\n                     if (!is_wp_error($user)) {\n \u002F\u002F                        wp_clear_auth_cookie();\n@@ -714,6 +729,21 @@\n                     ]);\n                 } else {\n \u002F\u002F                if($response=='true') {\n+                    \u002F\u002F ONLY validate phone number if this is Firebase authentication\n+                    if (isset($_GET['method']) && $_GET['method'] === 'firebase') {\n+                        $firebase_phone = isset($response->phoneNumber) ? ltrim($response->phoneNumber, '+') : '';\n+                        $requested_phone = $phone_number;\n+\n+                        if (empty($firebase_phone) || (\n+                                $firebase_phone !== $requested_phone &&\n+                                !str_ends_with($firebase_phone, $requested_phone)\n+                            )) {\n+                            wp_send_json([\n+                                'success' => false,\n+                                'message' => __('Phone number mismatch. Verification failed.', 'login-with-phone-number')\n+                            ]);\n+                        }\n+                    }\n                     $user = get_user_by('ID', $username_exists);\n                     if (!is_wp_error($user)) {\n \u002F\u002F                        wp_clear_auth_cookie();","The exploit targets the `lwp_ajax_register` or `lwp_ajax_login` AJAX actions, which are available to unauthenticated users. \n\n1.  **Preparation**: The attacker identifies the phone number of a target user (e.g., an administrator) stored in the WordPress database.\n2.  **Nonce Acquisition**: The attacker visits a public page where the plugin's login shortcode is active to extract a valid WordPress nonce from the localized JavaScript variable `userspn_ajax.nonce`.\n3.  **OTP Generation**: The attacker uses their own valid phone number and the site's Firebase configuration to complete a legitimate OTP flow, generating a valid Firebase `idToken` tied to the attacker's phone number.\n4.  **Payload Delivery**: The attacker sends a POST request to `\u002Fwp-admin\u002Fadmin-ajax.php` with the following parameters:\n    - `action`: `lwp_ajax_register` (or `lwp_ajax_login`)\n    - `username`: [Victim's phone number]\n    - `method`: `firebase`\n    - `idToken`: [Attacker's valid Firebase token]\n    - `nonce`: [Extracted nonce]\n5.  **Bypass**: The plugin verifies the `idToken` with Firebase, which returns success. Because the plugin does not check if the phone number in the token matches the `username` parameter, it proceeds to authenticate the attacker as the user associated with the victim's phone number.","gemini-3-flash-preview","2026-06-04 15:34:48","2026-06-04 15:36:02",{"type":40,"vulnerable_version":41,"fixed_version":11,"vulnerable_browse":42,"vulnerable_zip":43,"fixed_browse":44,"fixed_zip":45,"all_tags":46},"plugin","1.8.60","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Flogin-with-phone-number\u002Ftags\u002F1.8.60","https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Flogin-with-phone-number.1.8.60.zip","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Flogin-with-phone-number\u002Ftags\u002F1.8.61","https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Flogin-with-phone-number.1.8.61.zip","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Flogin-with-phone-number\u002Ftags"]