[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"$fRx08PFLg2e_UKhkJbUOTMgYUzChW1Nxczss7IuxQ8qc":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":25,"research_verified":26,"research_rounds_completed":27,"research_plan":28,"research_summary":9,"research_vulnerable_code":9,"research_fix_diff":9,"research_exploit_outline":9,"research_model_used":29,"research_started_at":30,"research_completed_at":31,"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":26,"poc_model_used":9,"poc_verification_depth":9,"poc_exploit_code_gated":26,"source_links":32},"CVE-2026-2374","login-no-captcha-recaptcha-unauthenticated-stored-cross-site-scripting-via-phpself","Login No Captcha reCAPTCHA \u003C= 1.8.0 - Unauthenticated Stored Cross-Site Scripting via PHP_SELF","The Login No Captcha reCAPTCHA plugin for WordPress is vulnerable to Stored Cross-Site Scripting via the `$_SERVER['PHP_SELF']` superglobal in all versions up to, and including, 1.8.0. This is due to the `authenticate()` function storing the unsanitized output of `basename($_SERVER['PHP_SELF'])` in the `login_nocaptcha_error` WordPress option when a login attempt is made from a non-standard login page (e.g., xmlrpc.php). The `admin_notices()` function then echoes this stored value directly into the admin dashboard HTML without escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts that execute when an administrator with a whitelisted IP address visits the WordPress dashboard within 30 seconds of the attack.","login-recaptcha",null,"\u003C=1.8.0","1.8.1","high",7.2,"CVSS:3.1\u002FAV:N\u002FAC:L\u002FPR:N\u002FUI:N\u002FS:C\u002FC:L\u002FI:L\u002FA:N","Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting')","2026-05-27 14:54:36","2026-05-28 03:27:27",[19],"https:\u002F\u002Fwww.wordfence.com\u002Fthreat-intel\u002Fvulnerabilities\u002Fid\u002F99dfce3b-2b47-41bf-8b20-b53fb9f061a7?source=api-prod",1,[22,23,24],"admin.php","login-nocaptcha.php","readme.txt","researched",false,3,"This research plan outlines the steps required to demonstrate the Unauthenticated Stored Cross-Site Scripting (XSS) vulnerability in the **Login No Captcha reCAPTCHA** plugin (CVE-2026-2374).\n\n### 1. Vulnerability Summary\nThe `Login No Captcha reCAPTCHA` plugin (up to version 1.8.0) is vulnerable to Stored XSS because it trusts the `$_SERVER['PHP_SELF']` value during authentication attempts on non-standard login pages (like `xmlrpc.php`). The `LoginNocaptcha::authenticate()` function retrieves the current script's name using `basename($_SERVER['PHP_SELF'])` and stores it into the `login_nocaptcha_error` WordPress option when it identifies a login attempt that bypasses the standard `wp-login.php` flow. This stored value is later rendered in the admin dashboard via the `admin_notices` hook without any output escaping, allowing an unauthenticated attacker to inject malicious scripts into the administrator's view.\n\n### 2. Attack Vector Analysis\n*   **Vulnerable Endpoint**: `\u002Fxmlrpc.php\u002F` (or any path that triggers the `authenticate` filter).\n*   **Vulnerable Parameter**: The URL path component of `PHP_SELF`.\n*   **Authentication**: None (Unauthenticated).\n*   **Preconditions**: \n    1.  The plugin must be configured with a valid-length (40 characters) Site Key and Secret Key to activate the `authenticate` filter.\n    2.  An administrator must visit the dashboard (`\u002Fwp-admin\u002F`) to trigger the payload.\n    3.  The payload must be triggered within the time window before the notice is cleared (the description suggests a 30-second window, likely due to the plugin's transient handling of error notices).\n\n### 3. Code Flow\n1.  **Initialization**: `LoginNocaptcha::init()` (in `login-nocaptcha.php`) checks if `login_nocaptcha_key` and `login_nocaptcha_secret` are set using `valid_key_secret()`.\n2.  **Hook Registration**: If keys are valid, it registers the `authenticate` filter: `add_filter('authenticate', array('LoginNocaptcha', 'authenticate'), 30, 3)`.\n3.  **Source (Input)**: An attacker requests `\u002Fxmlrpc.php\u002F\u003Cimg src=x onerror=alert(1)>`. WordPress populates `$_SERVER['PHP_SELF']` with the path including the payload.\n4.  **Processing**: The `authenticate()` function is called during the XML-RPC authentication attempt. It checks the current script: `basename($_SERVER['PHP_SELF'])`.\n5.  **Storage**: The function identifies the script is not `wp-login.php` and calls `update_option('login_nocaptcha_error', ...)` containing the malicious basename.\n6.  **Sink (Output)**: When an admin loads any admin page, `LoginNocaptcha::admin_notices()` is called. It retrieves the `login_nocaptcha_error` option and `echo`es it directly to the page without using `esc_html()` or `wp_kses()`.\n\n### 4. Nonce Acquisition Strategy\nThis vulnerability is **unauthenticated** and occurs during the authentication process itself (the `authenticate` filter). Therefore, **no WordPress nonce is required** to inject the payload.\n\n### 5. Exploitation Strategy\nThe goal is to store an XSS payload in the `login_nocaptcha_error` option by making a failed login attempt via XML-RPC.\n\n**Step 1: Configure the Plugin**\nThe plugin only hooks the vulnerable filter if it believes it is correctly configured.\n```bash\n# Set dummy keys of 40 characters (required by valid_key_secret check)\nwp option update login_nocaptcha_key \"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\"\nwp option update login_nocaptcha_secret \"BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB\"\n```\n\n**Step 2: Inject the Payload**\nSend an XML-RPC request to a URL path containing the XSS payload. We use a standard XML-RPC system call to trigger the authentication flow.\n*   **URL**: `\u002Fxmlrpc.php\u002Ffoo\u003Cimg src=x onerror=alert(document.domain)>`\n*   **Method**: `POST`\n*   **Body**: A standard `wp.getUsersBlogs` XML-RPC call with dummy credentials.\n\n**Step 3: Trigger the XSS**\nLog in as an administrator and navigate to the dashboard.\n\n### 6. Test Data Setup\n1.  **Plugin Status**: Ensure `login-recaptcha` is installed and active.\n2.  **Admin User**: A standard administrator account (e.g., `admin` \u002F `password`).\n3.  **Keys**: Keys must be 40 chars long as per `LoginNocaptcha::valid_key_secret`.\n\n### 7. Expected Results\n*   The `POST` request to `\u002Fxmlrpc.php\u002F...` will return an XML response (likely an authentication failure).\n*   The WordPress option `login_nocaptcha_error` will now contain the string `foo\u003Cimg src=x onerror=alert(document.domain)>`.\n*   When the admin navigates to `\u002Fwp-admin\u002F`, an alert box displaying the document domain will appear.\n\n### 8. Verification Steps\nAfter sending the injection request, verify the database state using WP-CLI:\n```bash\nwp option get login_nocaptcha_error\n```\n*Expected Output*: The string should contain your HTML payload unencoded.\n\nTo verify the XSS via browser:\n1.  Use `browser_navigate` to `\u002Fwp-admin\u002F`.\n2.  Observe the execution of the JavaScript payload.\n\n### 9. Alternative Approaches\nIf `\u002Fxmlrpc.php\u002F` does not correctly populate `PHP_SELF` due to server configuration (e.g., Nginx without proper path info support), try:\n*   **Query String Injection**: Some environments might include the query string in `PHP_SELF` if not properly handled, though `basename()` usually mitigates this.\n*   **Direct Path**: If the site uses a custom login page provided by another plugin that triggers `authenticate()`, use that path.\n*   **Different Payload**: If `\u003Cimg ...>` is blocked by a WAF, try `\u003Cdetails open ontoggle=...>` or `\u003Csvg onload=...>` to avoid the `script` or `img` tags.\n\n### Payload for `http_request` (Step 2):\n```xml\n\u003C?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\u003CmethodCall>\n  \u003CmethodName>wp.getUsersBlogs\u003C\u002FmethodName>\n  \u003Cparams>\n    \u003Cparam>\u003Cvalue>\u003Cstring>attacker\u003C\u002Fstring>\u003C\u002Fvalue>\u003C\u002Fparam>\n    \u003Cparam>\u003Cvalue>\u003Cstring>password\u003C\u002Fstring>\u003C\u002Fvalue>\u003C\u002Fparam>\n  \u003C\u002Fparams>\n\u003C\u002FmethodCall>\n```\n**Request URL**: `http:\u002F\u002Flocalhost:8080\u002Fxmlrpc.php\u002Fx%3Cimg%20src=x%20onerror=alert(1)%3E`","gemini-3-flash-preview","2026-06-04 17:10:26","2026-06-04 17:11:35",{"type":33,"vulnerable_version":34,"fixed_version":11,"vulnerable_browse":35,"vulnerable_zip":36,"fixed_browse":37,"fixed_zip":38,"all_tags":39},"plugin","1.8","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Flogin-recaptcha\u002Ftags\u002F1.8","https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Flogin-recaptcha.1.8.zip","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Flogin-recaptcha\u002Ftags\u002F1.8.1","https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Flogin-recaptcha.1.8.1.zip","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Flogin-recaptcha\u002Ftags"]