[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"$fFZTUJ2LzwdT70MenLSWJGMdw4V55IQY119paTiSB-40":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-2026-25391","wp-wand-unlimited-content-generation-using-ai-for-openai-claude-openrouter-and-deepseek-missing-authorization","WP Wand – Unlimited Content Generation using AI – for OpenAI, Claude, Openrouter and Deepseek \u003C= 1.3.07 - Missing Authorization","The WP Wand – Unlimited Content Generation using AI – for OpenAI, Claude, Openrouter and Deepseek plugin for WordPress is vulnerable to unauthorized access due to a missing capability check on a function in versions up to, and including, 1.3.07. This makes it possible for authenticated attackers, with contributor-level access and above, to perform an unauthorized action.","ai-content-generation",null,"\u003C=1.3.07","medium",4.3,"CVSS:3.1\u002FAV:N\u002FAC:L\u002FPR:L\u002FUI:N\u002FS:U\u002FC:N\u002FI:L\u002FA:N","Missing Authorization","2026-01-30 00:00:00","2026-02-26 19:52:51",[18],"https:\u002F\u002Fwww.wordfence.com\u002Fthreat-intel\u002Fvulnerabilities\u002Fid\u002Fb74c99e7-e7e4-4bb6-a1e5-3ff7047400cd?source=api-prod",[],"researched",false,3,"As the source code for the plugin is not provided, this research plan is based on the vulnerability description, the patch diff (inferred), and standard WordPress plugin architecture. We will focus on identifying the specific AJAX handler that allows Contributor-level users to perform administrative actions.\n\n### 1. Vulnerability Summary\nThe **WP Wand** plugin (up to version 1.3.07) is vulnerable to **Missing Authorization**. The plugin registers AJAX handlers via the `wp_ajax_` hook but fails to perform an explicit `current_user_can( 'manage_options' )` check within the callback function. While `wp_ajax_` handlers require authentication, by default, they are accessible to any logged-in user (including Contributors and Subscribers). This allows a lower-privileged user to execute sensitive functions, such as modifying AI settings or API keys.\n\n### 2. Attack Vector Analysis\n*   **Endpoint:** `\u002Fwp-admin\u002Fadmin-ajax.php`\n*   **Action:** Likely related to setting updates or AI configuration (e.g., `wp_wand_save_settings`, `ai_content_generation_update_api_key` - *inferred*).\n*   **Parameter:** `action`, `nonce`, and the specific setting data (e.g., `openai_api_key`).\n*   **Authentication:** Contributor-level user.\n*   **Preconditions:** The attacker must have a valid login and a valid nonce (which is usually localized for the admin dashboard).\n\n### 3. Code Flow (Inferred)\n1.  **Entry Point:** An authenticated user sends a POST request to `admin-ajax.php` with an `action` parameter.\n2.  **Hook Registration:** The plugin likely uses a pattern similar to:\n    `add_action( 'wp_ajax_wp_wand_save_settings', array( $this, 'save_settings' ) );`\n3.  **The Handler:** Inside the `save_settings` function:\n    -   `check_ajax_referer( 'wp_wand_nonce', 'nonce' );` (The nonce check might exist, but it only prevents CSRF, not unauthorized access).\n    -   **Missing:** `if ( ! current_user_can( 'manage_options' ) ) wp_die();`\n    -   The function proceeds to update options via `update_option()`.\n\n### 4. Nonce Acquisition Strategy\nThe plugin likely enqueues scripts for its admin interface. Since Contributors can access the WordPress dashboard (`\u002Fwp-admin\u002F`), they can load the scripts and extract the nonce.\n\n1.  **Identify the Script Variable:** Search the plugin's main files for `wp_localize_script`. Look for a variable name like `wpWandData`, `aiContentGenData`, or `wp_wand_ajax`.\n2.  **Create a Target Page:** If the scripts only load on specific pages, the Contributor can still access them if the plugin doesn't restrict its menu items properly.\n3.  **Extraction:**\n    -   Navigate to `\u002Fwp-admin\u002Findex.php`.\n    -   Use `browser_eval` to find the nonce:\n        `browser_eval(\"window.wpWandData?.nonce || window.wp_wand_ajax?.nonce\")`\n4.  **Action Check:** Verify if the nonce action in `wp_create_nonce()` matches the verification in the handler. If the handler uses `check_ajax_referer( 'wp_wand_action', ... )`, the attacker needs that specific nonce.\n\n### 5. Exploitation Strategy\nWe will attempt to overwrite the plugin's API key setting, effectively disabling the AI generation or redirecting it.\n\n**Step 1: Reconnaissance**\nIdentify the exact AJAX action.\n`grep -r \"wp_ajax_\" \u002Fvar\u002Fwww\u002Fhtml\u002Fwp-content\u002Fplugins\u002Fai-content-generation\u002F`\n\n**Step 2: Nonce Extraction**\nNavigate to the dashboard as a Contributor and extract the nonce using `browser_eval`.\n\n**Step 3: Unauthorized Request**\nSend the exploit request using `http_request`.\n\n*   **URL:** `http:\u002F\u002Flocalhost:8080\u002Fwp-admin\u002Fadmin-ajax.php`\n*   **Method:** `POST`\n*   **Headers:** `Content-Type: application\u002Fx-www-form-urlencoded`\n*   **Body:**\n    ```\n    action=wp_wand_save_settings&nonce=[EXTRACTED_NONCE]&openai_api_key=EXPLOITED_KEY_VALUE&other_settings=malicious\n    ```\n\n### 6. Test Data Setup\n1.  **Install Plugin:** Ensure `ai-content-generation` version 1.3.07 is installed.\n2.  **Create User:**\n    `wp user create attacker attacker@example.com --role=contributor --user_pass=password123`\n3.  **Initial Configuration:** Set a dummy API key as admin to verify it can be overwritten.\n    `wp option update wp_wand_settings '{\"openai_api_key\": \"original_key\"}'` (JSON structure inferred).\n\n### 7. Expected Results\n*   The AJAX request should return a successful status (e.g., `{\"success\": true}`).\n*   The plugin's option in the `wp_options` table should be updated with the `EXPLOITED_KEY_VALUE`.\n*   A Contributor, who should NOT have access to plugin settings, successfully modified global plugin configuration.\n\n### 8. Verification Steps\nAfter the `http_request`, verify the database state using WP-CLI:\n1.  Check the relevant option:\n    `wp option get wp_wand_settings`\n2.  Verify the `openai_api_key` field contains the attacker-supplied value.\n\n### 9. Alternative Approaches\n*   **Direct Option Manipulation:** If the plugin uses `update_option` on a dynamic key provided in the POST body (e.g., `action=save_option&option_name=...&option_value=...`), check if any option can be overwritten (e.g., `users_can_register`).\n*   **Sensitive Data Leakage:** Look for AJAX actions that return settings (e.g., `wp_wand_get_settings`) without capability checks. This could leak the existing API keys.\n*   **Content Generation Exhaustion:** Triggering the `wp_wand_generate_content` action repeatedly as a Contributor to exhaust the site owner's AI credits\u002Fquota.","The WP Wand plugin for WordPress lacks capability checks on its AJAX handlers in versions up to 1.3.07. This allow authenticated users with Contributor-level access to perform administrative actions, such as updating API keys or plugin settings, by directly calling registered AJAX actions.","\u002F\u002F ai-content-generation\u002Fincludes\u002Fadmin\u002Fclass-wp-wand-admin.php (Inferred based on research plan)\n\nadd_action( 'wp_ajax_wp_wand_save_settings', array( $this, 'save_settings' ) );\n\npublic function save_settings() {\n    \u002F\u002F Nonce check might prevent CSRF, but lacks authorization for user roles\n    check_ajax_referer( 'wp_wand_nonce', 'nonce' );\n\n    \u002F\u002F Vulnerability: No current_user_can( 'manage_options' ) check performed before updating global state\n\n    if ( isset( $_POST['settings'] ) ) {\n        update_option( 'wp_wand_settings', $_POST['settings'] );\n    }\n    wp_send_json_success();\n}","--- a\u002Fai-content-generation\u002Fincludes\u002Fadmin\u002Fclass-wp-wand-admin.php\n+++ b\u002Fai-content-generation\u002Fincludes\u002Fadmin\u002Fclass-wp-wand-admin.php\n@@ -4,6 +4,10 @@\n     public function save_settings() {\n         check_ajax_referer( 'wp_wand_nonce', 'nonce' );\n \n+        if ( ! current_user_can( 'manage_options' ) ) {\n+            wp_send_json_error( array( 'message' => 'Unauthorized' ), 403 );\n+        }\n+\n         if ( isset( $_POST['settings'] ) ) {\n             update_option( 'wp_wand_settings', $_POST['settings'] );\n         }","To exploit this vulnerability, an attacker with Contributor-level access logs into the WordPress dashboard and extracts a valid AJAX nonce, typically localized into the page source by the plugin (e.g., via the 'wpWandData' or 'aiContentGenData' script variables). The attacker then sends a POST request to '\u002Fwp-admin\u002Fadmin-ajax.php' with the 'action' parameter set to 'wp_wand_save_settings' (or the relevant identified handler), providing the captured nonce and a payload containing malicious settings. Because the backend handler fails to verify if the user has administrative privileges (manage_options), it will process the request and update the plugin's configuration, such as overwriting API keys for OpenAI or Claude.","gemini-3-flash-preview","2026-05-04 20:43:23","2026-05-04 20:43:38",{"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\u002Fai-content-generation\u002Ftags"]