[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"$fhck5G7hkpD2FP0oI2gtdcohw97VHVgjsFuT2be0oNkw":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-25419","upsellwp-missing-authorization","UpsellWP \u003C= 2.2.3 - Missing Authorization","The UpsellWP plugin for WordPress is vulnerable to unauthorized access due to a missing capability check on a function in versions up to, and including, 2.2.3. This makes it possible for authenticated attackers, with subscriber-level access and above, to perform an unauthorized action.","checkout-upsell-and-order-bumps",null,"\u003C=2.2.3","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-28 00:00:00","2026-02-26 19:55:38",[18],"https:\u002F\u002Fwww.wordfence.com\u002Fthreat-intel\u002Fvulnerabilities\u002Fid\u002Fee6ffb62-0dfd-40c1-8fde-8705d99d4144?source=api-prod",[],"researched",false,3,"Since the source code for version 2.2.3 is not provided, this research plan is based on the vulnerability description, the plugin's known architecture (slug: `checkout-upsell-and-order-bumps`), and common \"Missing Authorization\" patterns in WooCommerce-related plugins.\n\n### 1. Vulnerability Summary\nThe **UpsellWP** plugin (\u003C= 2.2.3) fails to implement proper capability checks on one or more of its AJAX or admin-side handlers. While these handlers are intended for administrative use (managing upsells and order bumps), they are registered in a way that allows any authenticated user—including those with **Subscriber** roles—to trigger them. This allows an attacker to modify plugin settings, create malicious offers, or disrupt the store's checkout flow.\n\n### 2. Attack Vector Analysis\n*   **Endpoint:** `wp-admin\u002Fadmin-ajax.php`\n*   **Action:** Likely `upsell_wp_save_settings`, `upsell_wp_update_offer`, or `upsell_wp_toggle_offer_status` (inferred).\n*   **Authentication:** Authenticated (Subscriber or higher).\n*   **Payload Parameter:** `action`, `nonce` (if checked), and data parameters (e.g., `settings_data` or `offer_id`).\n*   **Preconditions:** The attacker must have a valid Subscriber-level session cookie.\n\n### 3. Code Flow (Inferred)\n1.  **Entry Point:** The plugin registers an AJAX action in its main class or an admin-specific class:\n    ```php\n    add_action( 'wp_ajax_upsell_wp_save_settings', [ $this, 'save_settings_callback' ] );\n    ```\n2.  **Missing Check:** Inside `save_settings_callback`, the code likely performs a nonce check but fails to call `current_user_can( 'manage_options' )`.\n3.  **Sink:** The function proceeds to update the database using `update_option()` or `$wpdb->update()` based on values provided in `$_POST`.\n\n### 4. Nonce Acquisition Strategy\nMany WooCommerce plugins localize nonces for the admin dashboard. Since Subscribers can access `wp-admin\u002Fprofile.php`, we must check if the plugin enqueues its scripts globally in the admin area.\n\n1.  **Identify Nonce Action:** Grep for `wp_create_nonce` in the plugin folder to find the action string (e.g., `upsell-wp-nonce`).\n2.  **Identify JS Variable:** Grep for `wp_localize_script` to find the object name (e.g., `upsell_wp_vars`).\n3.  **Extraction:**\n    *   Create a Subscriber user and log in.\n    *   Navigate to `wp-admin\u002Fprofile.php`.\n    *   Use `browser_eval` to extract the nonce:\n        `browser_eval(\"window.upsell_wp_vars?.nonce\")` (inferred name).\n4.  **Bypass Check:** If `check_ajax_referer` uses a generic action like `-1` or is missing entirely, the nonce may be unnecessary or easily obtained.\n\n### 5. Exploitation Strategy\nWe will attempt to disable an existing order bump or change a global setting to demonstrate unauthorized modification.\n\n**Step 1: Identify Target Setting**\nUse WP-CLI to find current settings:\n`wp option get upsell_wp_settings` (inferred name).\n\n**Step 2: Prepare Payload**\nWe will target an action like saving settings.\n\n*   **Request Method:** POST\n*   **URL:** `http:\u002F\u002Flocalhost:8080\u002Fwp-admin\u002Fadmin-ajax.php`\n*   **Content-Type:** `application\u002Fx-www-form-urlencoded`\n*   **Parameters:**\n    *   `action`: `upsell_wp_save_settings` (inferred)\n    *   `upsell_wp_nonce`: `[EXTRACTED_NONCE]`\n    *   `settings`: `{\"enable_upsells\":\"0\"}` (example payload to disable the plugin's main feature)\n\n**Step 3: Execute via http_request**\nUsing the Subscriber's cookies.\n\n### 6. Test Data Setup\n1.  **Plugin Setup:** Install UpsellWP 2.2.3 and WooCommerce.\n2.  **Configuration:** Create at least one \"Order Bump\" or \"Checkout Upsell\" via the admin UI.\n3.  **Attacker User:**\n    ```bash\n    wp user create attacker attacker@example.com --role=subscriber --user_pass=password123\n    ```\n4.  **Confirm Target State:**\n    ```bash\n    wp option get upsell_wp_settings\n    ```\n\n### 7. Expected Results\n*   **HTTP Response:** The server should return a `200 OK` with a success indicator (e.g., `{\"success\":true}` or `1`).\n*   **Impact:** The targeted setting (e.g., `enable_upsells`) should be modified in the database despite the request coming from a Subscriber.\n\n### 8. Verification Steps\nAfter sending the HTTP request, verify the change using WP-CLI:\n```bash\n# Verify the option value has changed\nwp option get upsell_wp_settings\n\n# Or verify via database directly if options are serialized\nwp db query \"SELECT option_value FROM wp_options WHERE option_name = 'upsell_wp_settings'\"\n```\n\n### 9. Alternative Approaches\nIf `upsell_wp_save_settings` is not the vulnerable action, the researcher should use the following commands to find other candidates:\n\n1.  **List all AJAX actions registered by the plugin:**\n    ```bash\n    grep -r \"wp_ajax_\" wp-content\u002Fplugins\u002Fcheckout-upsell-and-order-bumps\u002F\n    ```\n2.  **Analyze the callbacks for those actions:**\n    Search for callbacks that **DO NOT** contain the string `current_user_can`.\n    ```bash\n    # Example: Check if the 'save_offer' function has auth checks\n    grep -A 15 \"function save_offer\" wp-content\u002Fplugins\u002Fcheckout-upsell-and-order-bumps\u002Fpath\u002Fto\u002Ffile.php\n    ```\n3.  **Check `admin_init` hooks:**\n    Some plugins handle form submissions via `admin_init`. Since `admin_init` runs for all authenticated users (including subscribers) when they access `admin-ajax.php` or `admin-post.php`, handlers registered here without capability checks are highly vulnerable.\n    ```bash\n    grep -r \"add_action.*admin_init\" wp-content\u002Fplugins\u002Fcheckout-upsell-and-order-bumps\u002F\n    ```","The UpsellWP plugin for WordPress fails to perform capability checks on its AJAX handlers in versions up to 2.2.3. This allows authenticated users with Subscriber-level permissions to modify plugin settings or manipulate WooCommerce upsell offers by sending crafted requests to the WordPress AJAX endpoint.","\u002F\u002F Inferred code structure based on common patterns in the affected plugin version\n\u002F\u002F Path: wp-content\u002Fplugins\u002Fcheckout-upsell-and-order-bumps\u002Fincludes\u002Fadmin\u002Fclass-upsell-wp-admin.php\n\npublic function save_settings_callback() {\n    \u002F\u002F Nonce check might exist, but capability check is missing\n    check_ajax_referer('upsell-wp-nonce', 'nonce');\n\n    \u002F\u002F Vulnerability: No call to current_user_can('manage_options') before processing data\n    $settings = isset($_POST['settings']) ? $_POST['settings'] : array();\n    update_option('upsell_wp_settings', $settings);\n    \n    wp_send_json_success();\n}","--- wp-content\u002Fplugins\u002Fcheckout-upsell-and-order-bumps\u002Fincludes\u002Fadmin\u002Fclass-upsell-wp-admin.php\n+++ wp-content\u002Fplugins\u002Fcheckout-upsell-and-order-bumps\u002Fincludes\u002Fadmin\u002Fclass-upsell-wp-admin.php\n@@ -10,6 +10,10 @@\n public function save_settings_callback() {\n     check_ajax_referer('upsell-wp-nonce', 'nonce');\n \n+    if (!current_user_can('manage_options')) {\n+        wp_send_json_error('Unauthorized', 403);\n+    }\n+\n     $settings = isset($_POST['settings']) ? $_POST['settings'] : array();\n     update_option('upsell_wp_settings', $settings);\n     wp_send_json_success();","1. Login to the WordPress site as a user with Subscriber-level permissions.\n2. Access the WordPress admin dashboard (e.g., \u002Fwp-admin\u002Fprofile.php) and inspect the page source or use browser console to extract the AJAX nonce, typically localized by the plugin (e.g., window.upsell_wp_vars.nonce).\n3. Construct a POST request to \u002Fwp-admin\u002Fadmin-ajax.php with the 'action' parameter set to the vulnerable handler (e.g., 'upsell_wp_save_settings').\n4. Include the extracted 'nonce' and a 'settings' payload designed to disable features or modify offer parameters.\n5. Send the request and verify the modification by checking the plugin's configuration via the UI or database (e.g., 'wp option get upsell_wp_settings').","gemini-3-flash-preview","2026-05-04 21:41:05","2026-05-04 21:41:21",{"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\u002Fcheckout-upsell-and-order-bumps\u002Ftags"]