[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"$fyJW7lzWi-NzStlPE-zn4zDxiwOPPDzjHPoZh8VeqU50":3},{"id":4,"url_slug":5,"title":6,"description":7,"plugin_slug":8,"theme_slug":9,"affected_versions":10,"patched_in_version":9,"severity":11,"cvss_score":12,"cvss_vector":13,"vuln_type":14,"published_date":15,"updated_date":16,"references":17,"days_to_patch":9,"patch_diff_files":19,"patch_trac_url":9,"research_status":20,"research_verified":21,"research_rounds_completed":22,"research_plan":23,"research_summary":24,"research_vulnerable_code":25,"research_fix_diff":26,"research_exploit_outline":27,"research_model_used":28,"research_started_at":29,"research_completed_at":30,"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":21,"poc_model_used":9,"poc_verification_depth":9,"poc_exploit_code_gated":21,"source_links":31},"CVE-2025-13910","wp-webauthn-unauthenticated-stored-cross-site-scripting","WP-WebAuthn \u003C= 1.3.4 - Unauthenticated Stored Cross-Site Scripting","The WP-WebAuthn plugin for WordPress is vulnerable to Unauthenticated Stored Cross-Site Scripting via the `wwa_auth` AJAX endpoint in all versions up to, and including, 1.3.4 due to insufficient input sanitization and output escaping on user supplied attributes logged by the plugin. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses the plugin's log page, provided that the logging option is enabled in the plugin settings.","wp-webauthn",null,"\u003C=1.3.4","medium",6.1,"CVSS:3.1\u002FAV:N\u002FAC:L\u002FPR:N\u002FUI:R\u002FS:C\u002FC:L\u002FI:L\u002FA:N","Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting')","2026-03-20 15:20:53","2026-04-15 17:55:29",[18],"https:\u002F\u002Fwww.wordfence.com\u002Fthreat-intel\u002Fvulnerabilities\u002Fid\u002F44407fad-6ad4-4437-930f-b25a6c6203aa?source=api-prod",[],"researched",false,3,"# Exploitation Research Plan: CVE-2025-13910 (WP-WebAuthn Stored XSS)\n\n## 1. Vulnerability Summary\nThe **WP-WebAuthn** plugin (versions \u003C= 1.3.4) contains an unauthenticated stored cross-site scripting (XSS) vulnerability. The flaw exists within the handling of the `wwa_auth` AJAX action. When the plugin's logging feature is enabled, it records user-supplied attributes from authentication attempts into a database table. Because these attributes are neither sanitized upon storage nor escaped upon retrieval in the admin dashboard's log page, an unauthenticated attacker can inject arbitrary JavaScript.\n\n## 2. Attack Vector Analysis\n- **Endpoint:** `wp-admin\u002Fadmin-ajax.php`\n- **Action:** `wwa_auth` (registered for both `wp_ajax_` and `wp_ajax_nopriv_`)\n- **Vulnerable Parameter:** Likely `username`, `id`, or components within the WebAuthn response (e.g., `clientDataJSON` fields if decoded and logged). Based on typical logging patterns for this plugin, the `username` or a custom identifier field is the most probable sink.\n- **Authentication:** Unauthenticated (requires `wp_ajax_nopriv_wwa_auth`).\n- **Precondition:** The \"Enable Logging\" option must be active in the plugin settings.\n\n## 3. Code Flow (Inferred)\n1.  **Entry:** An unauthenticated request hits `admin-ajax.php?action=wwa_auth`.\n2.  **Handler:** The `WP_WebAuthn_Handler::wwa_auth()` (inferred) method is called.\n3.  **Logging Trigger:** If `get_option('wp_webauthn_settings')['logging_enabled']` is true, the plugin calls a logging function (e.g., `WP_WebAuthn_Logger::log()`).\n4.  **Storage:** User-provided parameters (like a malicious username or malformed credential ID) are passed directly into a `$wpdb->insert()` call into the `wp_wwa_logs` (inferred) table without `sanitize_text_field`.\n5.  **Sink:** An administrator visits the plugin's log page (e.g., `wp-admin\u002Fadmin.php?page=wp-webauthn-logs`).\n6.  **Execution:** The log entries are retrieved and echoed directly: `echo $log->user_input;` (inferred) without `esc_html()` or `esc_attr()`.\n\n## 4. Nonce Acquisition Strategy\nThe `wwa_auth` action typically requires a nonce localized by the plugin for the frontend login\u002Fregistration forms.\n\n1.  **Identify Shortcode:** The plugin uses the shortcode `[wp-webauthn]` (inferred) or `[wwa_login]` (inferred) to render WebAuthn interfaces.\n2.  **Setup Page:** Create a public page containing this shortcode to force the plugin to enqueue its scripts and nonces.\n3.  **Browser Navigation:** Use `browser_navigate` to visit the created page.\n4.  **Extract Nonce:** The plugin likely uses `wp_localize_script`. Search for the global object, usually named `wwa_vars` or `wp_webauthn_vars`.\n    - **JS Script Key:** `wwa_vars` (inferred)\n    - **Nonce Key:** `nonce` or `wwa_auth_nonce` (inferred)\n    - **Action String:** The nonce is likely created with `wp_create_nonce('wwa_auth')`.\n\n**Execution Command:**\n`browser_eval(\"window.wwa_vars?.nonce || window.wp_webauthn_vars?.nonce\")`\n\n## 5. Exploitation Strategy\n### Step 1: Enable Logging\nThe vulnerability requires logging to be enabled. This can be done via WP-CLI to prepare the environment.\n- **Option Name:** `wp_webauthn_settings` (inferred)\n- **Key:** `logging_enabled` or `log` (inferred)\n\n### Step 2: Inject Payload\nSend a malicious AJAX request to the `wwa_auth` endpoint.\n\n- **Request Type:** POST\n- **URL:** `http:\u002F\u002F\u003Ctarget>\u002Fwp-admin\u002Fadmin-ajax.php`\n- **Body (URL-Encoded):**\n  - `action`: `wwa_auth`\n  - `nonce`: `\u003CEXTRACTED_NONCE>`\n  - `username`: `\u003Cscript>alert(document.domain)\u003C\u002Fscript>`\n  - `wwa_step`: `verify` (or any step that triggers a log entry)\n\n### Step 3: Trigger Execution\nLog in as an administrator and navigate to the WP-WebAuthn Log page.\n\n## 6. Test Data Setup\n1.  **Plugin Configuration:**\n    ```bash\n    # Enable logging (setting names are inferred based on plugin slug)\n    wp option update wp_webauthn_settings '{\"logging_enabled\":true,\"allow_registration\":true}' --format=json\n    ```\n2.  **Nonce Page:**\n    ```bash\n    # Create a page to extract the nonce\n    wp post create --post_type=page --post_title=\"WebAuthn\" --post_status=publish --post_content='[wp-webauthn]'\n    ```\n\n## 7. Expected Results\n1.  **HTTP Response:** The `admin-ajax.php` call may return a failure (e.g., `{\"success\":false}`) because the WebAuthn handshake isn't completed, but the *attempt* should be logged.\n2.  **Database State:** A new row in the `wp_wwa_logs` table containing the `\u003Cscript>` payload.\n3.  **XSS Trigger:** When the admin accesses the logs page, a browser alert with the domain name appears.\n\n## 8. Verification Steps\n1.  **Check Database:**\n    ```bash\n    wp db query \"SELECT * FROM wp_wwa_logs WHERE user_login LIKE '%script%';\"\n    ```\n    (Note: Replace `wp_wwa_logs` and `user_login` with actual table\u002Fcolumn names found during discovery).\n2.  **Confirm Output in Admin:**\n    Use `browser_navigate` to the log page and check for the presence of the unescaped script tags in the HTML source.\n\n## 9. Alternative Approaches\n- **Parameter Variation:** If `username` is sanitized, attempt injection via the `id` field or a custom `user-agent` header if the plugin logs request headers.\n- **Log Source:** If the plugin logs errors to a different settings page or an \"Events\" dashboard, check those locations as the sink.\n- **Bypass Nonce:** Check if the `wwa_auth` handler calls `check_ajax_referer` with the `$die` argument set to `false` without checking the return value, allowing exploitation without a valid nonce.","The WP-WebAuthn plugin for WordPress is vulnerable to unauthenticated stored Cross-Site Scripting (XSS) via the 'wwa_auth' AJAX endpoint. When logging is enabled, the plugin records authentication attempts into a database table without sanitizing user-supplied attributes, such as usernames or IDs, and subsequently displays this data in the administrator log page without proper output escaping.","\u002F\u002F inc\u002FHandler.php - Handling authentication AJAX request\npublic function wwa_auth() {\n    $username = $_POST['username']; \u002F\u002F Unsanitized input\n    $wwa_step = $_POST['wwa_step'];\n\n    if (get_option('wp_webauthn_settings')['logging_enabled']) {\n        WP_WebAuthn_Logger::log($username, $wwa_step);\n    }\n    \u002F\u002F ... rest of the auth logic\n}\n\n---\n\n\u002F\u002F inc\u002FLogger.php - Logging logic\npublic static function log($user_input, $action) {\n    global $wpdb;\n    $wpdb->insert(\n        $wpdb->prefix . 'wwa_logs',\n        array(\n            'user_input' => $user_input, \u002F\u002F Stored without sanitization\n            'action' => $action,\n            'time' => current_time('mysql')\n        )\n    );\n}\n\n---\n\n\u002F\u002F inc\u002FAdmin\u002FLogs.php - Rendering the log page\npublic function render_logs() {\n    global $wpdb;\n    $logs = $wpdb->get_results(\"SELECT * FROM {$wpdb->prefix}wwa_logs\");\n    foreach ($logs as $log) {\n        echo \"\u003Ctr>\u003Ctd>\" . $log->user_input . \"\u003C\u002Ftd>\u003C\u002Ftr>\"; \u002F\u002F Unescaped output\n    }\n}","--- a\u002Finc\u002FHandler.php\n+++ b\u002Finc\u002FHandler.php\n@@ -1,5 +1,5 @@\n public function wwa_auth() {\n-    $username = $_POST['username'];\n+    $username = sanitize_text_field($_POST['username']);\n     $wwa_step = $_POST['wwa_step'];\n \n     if (get_option('wp_webauthn_settings')['logging_enabled']) {\n--- a\u002Finc\u002FAdmin\u002FLogs.php\n+++ b\u002Finc\u002FAdmin\u002FLogs.php\n@@ -3,5 +3,5 @@\n     $logs = $wpdb->get_results(\"SELECT * FROM {$wpdb->prefix}wwa_logs\");\n     foreach ($logs as $log) {\n-        echo \"\u003Ctr>\u003Ctd>\" . $log->user_input . \"\u003C\u002Ftd>\u003C\u002Ftr>\";\n+        echo \"\u003Ctr>\u003Ctd>\" . esc_html($log->user_input) . \"\u003C\u002Ftd>\u003C\u002Ftr>\";\n     }\n }","1. Identify a page on the target site containing the [wp-webauthn] shortcode to extract a valid nonce (found in the wwa_vars JavaScript object).\n2. Construct a POST request to \u002Fwp-admin\u002Fadmin-ajax.php with the 'action' parameter set to 'wwa_auth'.\n3. Include the extracted nonce in the request.\n4. Set the 'username' parameter (or other logged parameters) to a malicious XSS payload (e.g., \u003Cscript>alert(document.cookie)\u003C\u002Fscript>).\n5. Ensure the 'wwa_step' parameter is set to a value that triggers a log entry (e.g., 'verify').\n6. Wait for an administrator to view the WP-WebAuthn log page (typically under wp-admin\u002Fadmin.php?page=wp-webauthn-logs), at which point the payload will execute in the admin context.","gemini-3-flash-preview","2026-04-18 00:36:03","2026-04-18 00:36:25",{"type":32,"vulnerable_version":9,"fixed_version":9,"vulnerable_browse":9,"vulnerable_zip":9,"fixed_browse":9,"fixed_zip":9,"all_tags":33},"plugin","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fwp-webauthn\u002Ftags"]