[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"$f7sOTy3jT2wxNLWeTWZ1EH2FS2OexVFn5PR7UvkkMx3k":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-48839","wp-statistics-simple-privacy-friendly-google-analytics-alternative-unauthenticated-stored-cross-site-scripting","WP Statistics – Simple, privacy-friendly Google Analytics alternative \u003C= 14.16.6 - Unauthenticated Stored Cross-Site Scripting","The WP Statistics – Simple, privacy-friendly Google Analytics alternative plugin for WordPress is vulnerable to Stored Cross-Site Scripting in versions up to, and including, 14.16.6 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.","wp-statistics",null,"\u003C=14.16.6","14.16.7","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-01 00:00:00","2026-06-01 16:18:16",[19],"https:\u002F\u002Fwww.wordfence.com\u002Fthreat-intel\u002Fvulnerabilities\u002Fid\u002Fdd389d3b-046c-41cb-a077-7dcb9fd50eda?source=api-prod",1,[22,23,24,25,26,27,28,29],"includes\u002Fadmin\u002Ftemplates\u002Foptimization\u002Fupdates.php","includes\u002Fadmin\u002Ftemplates\u002Fpages\u002Fdevices\u002Fbrowsers.php","includes\u002Fadmin\u002Ftemplates\u002Fpages\u002Fdevices\u002Fcategories.php","includes\u002Fadmin\u002Ftemplates\u002Fpages\u002Fdevices\u002Fplatforms.php","includes\u002Fapi\u002Fv2\u002Fclass-wp-statistics-api-hit.php","languages\u002Fwp-statistics.pot","readme.txt","src\u002FComponents\u002FAssetNameObfuscator.php","researched",false,3,"This research plan outlines the steps to investigate and exploit a Stored Cross-Site Scripting (XSS) vulnerability in the **WP Statistics** plugin (versions \u003C= 14.16.6).\n\n---\n\n### 1. Vulnerability Summary\n*   **Vulnerability:** Unauthenticated Stored Cross-Site Scripting (XSS).\n*   **Location:** Visitor statistics recording logic and subsequent admin dashboard rendering.\n*   **Cause:** The plugin records visitor details (Browser, Platform, Device) based on the `User-Agent` header. These values are stored in the database and later displayed in the WordPress admin dashboard templates (e.g., `browsers.php`, `categories.php`, `platforms.php`) without sufficient output escaping.\n*   **Affected Files:**\n    *   `includes\u002Fadmin\u002Ftemplates\u002Fpages\u002Fdevices\u002Fbrowsers.php`\n    *   `includes\u002Fadmin\u002Ftemplates\u002Fpages\u002Fdevices\u002Fcategories.php`\n    *   `includes\u002Fadmin\u002Ftemplates\u002Fpages\u002Fdevices\u002Fplatforms.php`\n    *   `includes\u002Fapi\u002Fv2\u002Fclass-wp-statistics-api-hit.php` (REST API hit endpoint)\n\n### 2. Attack Vector Analysis\n*   **Endpoint:** Either the main site frontend (triggering automatic tracking) or the REST API endpoint `\u002Fwp-json\u002Fwp-statistics\u002Fv2\u002Fhit`.\n*   **Payload Location:** The `User-Agent` HTTP request header.\n*   **Authentication:** None (Unauthenticated).\n*   **Preconditions:**\n    *   The plugin must be active and configured to track visits.\n    *   For the REST API attack: The \"Cache Plugin\" setting (`use_cache_plugin`) must be enabled.\n\n### 3. Code Flow\n1.  **Entry Point (REST):** `WP_STATISTICS\\Api\\v2\\Hit::hit_callback()` is triggered via a `POST` request to `wp-json\u002Fwp-statistics\u002Fv2\u002Fhit`.\n2.  **Processing:** `hit_callback()` calls `WP_STATISTICS\\Hits::record()`.\n3.  **Storage:** `Hits::record()` extracts the `User-Agent` from the environment, uses a parser (likely `DeviceHelper`) to determine the browser\u002Fplatform\u002Fdevice, and stores these strings in the database (typically the `{prefix}statistics_visitor` table).\n4.  **Admin Rendering:** An administrator navigates to **WP Statistics > Optimization** or specific device reports.\n5.  **Sink:** The template `includes\u002Fadmin\u002Ftemplates\u002Fpages\u002Fdevices\u002Fbrowsers.php` (and others) iterates through the stored visitors.\n6.  **XSS Trigger:** The code executes:\n    ```php\n    \u003Cspan title=\"\u003C?php echo \\WP_STATISTICS\\Admin_Template::unknownToNotSet($item->agent); ?>\" ...>\n        ...\n        \u003C?php echo \\WP_STATISTICS\\Admin_Template::unknownToNotSet($item->agent); ?>\n    \u003C\u002Fspan>\n    ```\n    The function `unknownToNotSet()` merely returns the string if it is not \"unknown\". Since there is no `esc_html()` or `esc_attr()` surrounding the echo, the payload executes in the admin's browser.\n\n### 4. Nonce Acquisition Strategy\nIf attacking via the REST API (`hit` endpoint), a signature check is performed:\n1.  **Action String:** The REST route uses `checkSignature($request)`.\n2.  **Acquisition:**\n    *   Identify a page where WP Statistics tracking is active (usually all public pages).\n    *   Use `browser_navigate` to visit the homepage.\n    *   WP Statistics typically localizes data for its frontend script. Use `browser_eval` to look for variables like `wp_statistics_tracker` or `WP_Statistics_L10n`.\n    *   Specific to REST: Check `window.WP_Statistics_REST_Config?.nonce` or similar.\n3.  **Fallback:** The vulnerability is \"unauthenticated\" because simple visits to the homepage with a spoofed `User-Agent` are recorded by the plugin's standard hook into `wp` or `template_redirect` if the REST hit API is not being used.\n\n### 5. Exploitation Strategy\n\n#### Method A: Direct Visit (Recommended)\n1.  **Payload:** `Mozilla\u002F5.0 (X11; Linux x86_64) \u003Cscript>alert(document.domain)\u003C\u002Fscript>`\n2.  **Request:** Use `http_request` to send a `GET` request to the WordPress homepage.\n3.  **Headers:** Set the `User-Agent` header to the payload above.\n4.  **Wait:** The plugin may record hits asynchronously or on the next tick; usually, it is immediate.\n\n#### Method B: REST API (If Method A fails)\n1.  **Endpoint:** `POST \u002Fwp-json\u002Fwp-statistics\u002Fv2\u002Fhit`\n2.  **Headers:**\n    *   `User-Agent`: `\">\u003Cimg src=x onerror=alert(1)>`\n    *   `Content-Type`: `application\u002Fx-www-form-urlencoded`\n3.  **Body Parameters:**\n    *   `page_uri`: `\u002F`\n    *   `_wpnonce`: (Acquired from JS context if signature check is enforced)\n\n### 6. Test Data Setup\n1.  **Install Plugin:** `wp plugin install wp-statistics --version=14.16.6 --activate`\n2.  **Enable Tracking:** Ensure tracking is enabled (default behavior).\n3.  **Optional:** To test the REST hit path, enable the cache setting:\n    `wp option patch update wp_statistics_options use_cache_plugin 1`\n\n### 7. Expected Results\n*   The `http_request` should return a `200 OK` (for Method A) or a JSON success response (for Method B).\n*   When an administrator views the \"Browsers\" or \"Devices\" report, the injected script will execute.\n\n### 8. Verification Steps\n1.  **Check Database:** Use WP-CLI to verify the payload is stored:\n    `wp db query \"SELECT agent FROM $(wp db prefix)statistics_visitor ORDER BY ID DESC LIMIT 1;\"`\n2.  **Confirm Sink:** Navigate to the browser report page as an admin:\n    `browser_navigate(\"http:\u002F\u002Flocalhost:8080\u002Fwp-admin\u002Fadmin.php?page=wp-statistics-browsers\")`\n3.  **Verify Execution:** Use `browser_eval` to check for a global flag set by your payload (if using a more complex payload than `alert`).\n\n### 9. Alternative Approaches\n*   **Platform Payload:** If the browser parser filters certain characters, try targeting the Platform field by crafting a User-Agent that triggers a specific OS detection followed by the payload.\n*   **Device Category:** Target `categories.php` by crafting a User-Agent that mimics a mobile device with an injected string.\n*   **Search Engine XSS:** Check if the \"Search Engines\" or \"Referrals\" reports are also vulnerable by spoofing the `Referer` header with an XSS payload in the query parameters of a search engine URL.","The WP Statistics plugin for WordPress is vulnerable to unauthenticated Stored Cross-Site Scripting (XSS) due to a failure to sanitize and escape visitor information derived from the User-Agent header. An attacker can inject malicious scripts by visiting the site with a crafted User-Agent, which is then executed in the context of an administrator's browser when they view visitor reports.","\u002F\u002F includes\u002Fadmin\u002Ftemplates\u002Fpages\u002Fdevices\u002Fbrowsers.php lines 39-42\n\u003Cspan title=\"\u003C?php echo \\WP_STATISTICS\\Admin_Template::unknownToNotSet($item->agent); ?>\" class=\"wps-browser-name\">\n    \u003Cimg alt=\"\u003C?php echo \\WP_STATISTICS\\Admin_Template::unknownToNotSet($item->agent); ?>\" src=\"\u003C?php echo esc_url(DeviceHelper::getBrowserLogo($item->agent)); ?>\" class=\"log-tools wps-flag\"\u002F>\n    \u003C?php echo \\WP_STATISTICS\\Admin_Template::unknownToNotSet($item->agent); ?>\n\u003C\u002Fspan>\n\n---\n\n\u002F\u002F includes\u002Fadmin\u002Ftemplates\u002Fpages\u002Fdevices\u002Fcategories.php lines 35-37\n\u003Cspan title=\"\u003C?php echo \\WP_STATISTICS\\Admin_Template::unknownToNotSet($item->device); ?>\" class=\"wps-model-name\">\n    \u003C?php echo \\WP_STATISTICS\\Admin_Template::unknownToNotSet($item->device); ?>\n\u003C\u002Fspan>\n\n---\n\n\u002F\u002F includes\u002Fadmin\u002Ftemplates\u002Fpages\u002Fdevices\u002Fplatforms.php lines 36-39\n\u003Cspan title=\"\u003C?php echo \\WP_STATISTICS\\Admin_Template::unknownToNotSet($item->platform); ?>\" class=\"wps-platform-name\">\n    \u003Cimg alt=\"\u003C?php echo \\WP_STATISTICS\\Admin_Template::unknownToNotSet($item->platform); ?>\" src=\"\u003C?php echo esc_url(DeviceHelper::getPlatformLogo($item->platform)); ?>\" class=\"log-tools wps-flag\"\u002F>\n    \u003C?php echo \\WP_STATISTICS\\Admin_Template::unknownToNotSet($item->platform); ?>\n\u003C\u002Fspan>","diff -ru \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fwp-statistics\u002F14.16.6\u002Fincludes\u002Fadmin\u002Ftemplates\u002Fpages\u002Fdevices\u002Fbrowsers.php \u002Fhome\u002Fdeploy\u002Fwp-statistics\u002F14.16.7\u002Fincludes\u002Fadmin\u002Ftemplates\u002Fpages\u002Fdevices\u002Fbrowsers.php\n--- \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fwp-statistics\u002F14.16.6\u002Fincludes\u002Fadmin\u002Ftemplates\u002Fpages\u002Fdevices\u002Fbrowsers.php\n+++ \u002Fhome\u002Fdeploy\u002Fwp-statistics\u002F14.16.7\u002Fincludes\u002Fadmin\u002Ftemplates\u002Fpages\u002Fdevices\u002Fbrowsers.php\n@@ -36,9 +36,9 @@\n                                 \u003C?php foreach ($data['visitors'] as $item) : ?>\n                                     \u003Ctr>\n                                         \u003Ctd class=\"wps-pd-l\">\n-                                                \u003Cspan title=\"\u003C?php echo \\WP_STATISTICS\\Admin_Template::unknownToNotSet($item->agent); ?>\" class=\"wps-browser-name\">\n-                                                    \u003Cimg alt=\"\u003C?php echo \\WP_STATISTICS\\Admin_Template::unknownToNotSet($item->agent); ?>\" src=\"\u003C?php echo esc_url(DeviceHelper::getBrowserLogo($item->agent)); ?>\" class=\"log-tools wps-flag\"\u002F>\n-                                                    \u003C?php echo \\WP_STATISTICS\\Admin_Template::unknownToNotSet($item->agent); ?>\n+                                                \u003Cspan title=\"\u003C?php echo esc_attr(\\WP_STATISTICS\\Admin_Template::unknownToNotSet($item->agent)); ?>\" class=\"wps-browser-name\">\n+                                                    \u003Cimg alt=\"\u003C?php echo esc_attr(\\WP_STATISTICS\\Admin_Template::unknownToNotSet($item->agent)); ?>\" src=\"\u003C?php echo esc_url(DeviceHelper::getBrowserLogo($item->agent)); ?>\" class=\"log-tools wps-flag\"\u002F>\n+                                                    \u003C?php echo esc_html(\\WP_STATISTICS\\Admin_Template::unknownToNotSet($item->agent)); ?>\n                                                 \u003C\u002Fspan>\n                                         \u003C\u002Ftd>\n                                         \u003Ctd class=\"wps-pd-l\">\ndiff -ru \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fwp-statistics\u002F14.16.6\u002Fincludes\u002Fadmin\u002Ftemplates\u002Fpages\u002Fdevices\u002Fcategories.php \u002Fhome\u002Fdeploy\u002Fwp-statistics\u002F14.16.7\u002Fincludes\u002Fadmin\u002Ftemplates\u002Fpages\u002Fdevices\u002Fcategories.php\n--- \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fwp-statistics\u002F14.16.6\u002Fincludes\u002Fadmin\u002Ftemplates\u002Fpages\u002Fdevices\u002Fcategories.php\n+++ \u002Fhome\u002Fdeploy\u002Fwp-statistics\u002F14.16.7\u002Fincludes\u002Fadmin\u002Ftemplates\u002Fpages\u002Fdevices\u002Fcategories.php\n@@ -32,8 +32,8 @@\n                                 \u003C?php foreach ($data['visitors'] as $item) : ?>\n                                     \u003Ctr>\n                                         \u003Ctd class=\"wps-pd-l\">\n-                                                \u003Cspan title=\"\u003C?php echo \\WP_STATISTICS\\Admin_Template::unknownToNotSet($item->device); ?>\" class=\"wps-model-name\">\n-                                                    \u003C?php echo \\WP_STATISTICS\\Admin_Template::unknownToNotSet($item->device); ?>\n+                                                \u003Cspan title=\"\u003C?php echo esc_attr(\\WP_STATISTICS\\Admin_Template::unknownToNotSet($item->device)); ?>\" class=\"wps-model-name\">\n+                                                    \u003C?php echo esc_html(\\WP_STATISTICS\\Admin_Template::unknownToNotSet($item->device)); ?>\n                                                 \u003C\u002Fspan>\n                                         \u003C\u002Ftd>\n                                         \u003Ctd class=\"wps-pd-l\">\ndiff -ru \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fwp-statistics\u002F14.16.6\u002Fincludes\u002Fadmin\u002Ftemplates\u002Fpages\u002Fdevices\u002Fplatforms.php \u002Fhome\u002Fdeploy\u002Fwp-statistics\u002F14.16.7\u002Fincludes\u002Fadmin\u002Ftemplates\u002Fpages\u002Fdevices\u002Fplatforms.php\n--- \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fwp-statistics\u002F14.16.6\u002Fincludes\u002Fadmin\u002Ftemplates\u002Fpages\u002Fdevices\u002Fplatforms.php\n+++ \u002Fhome\u002Fdeploy\u002Fwp-statistics\u002F14.16.7\u002Fincludes\u002Fadmin\u002Ftemplates\u002Fpages\u002Fdevices\u002Fplatforms.php\n@@ -33,9 +33,9 @@\n                                 \u003C?php foreach ($data['visitors'] as $item) : ?>\n                                     \u003Ctr>\n                                         \u003Ctd class=\"wps-pd-l\">\n-                                                \u003Cspan title=\"\u003C?php echo \\WP_STATISTICS\\Admin_Template::unknownToNotSet($item->platform); ?>\" class=\"wps-platform-name\">\n-                                                    \u003Cimg alt=\"\u003C?php echo \\WP_STATISTICS\\Admin_Template::unknownToNotSet($item->platform); ?>\" src=\"\u003C?php echo esc_url(DeviceHelper::getPlatformLogo($item->platform)); ?>\" class=\"log-tools wps-flag\"\u002F>\n-                                                    \u003C?php echo \\WP_STATISTICS\\Admin_Template::unknownToNotSet($item->platform); ?>\n+                                                \u003Cspan title=\"\u003C?php echo esc_attr(\\WP_STATISTICS\\Admin_Template::unknownToNotSet($item->platform)); ?>\" class=\"wps-platform-name\">\n+                                                    \u003Cimg alt=\"\u003C?php echo esc_attr(\\WP_STATISTICS\\Admin_Template::unknownToNotSet($item->platform)); ?>\" src=\"\u003C?php echo esc_url(DeviceHelper::getPlatformLogo($item->platform)); ?>\" class=\"log-tools wps-flag\"\u002F>\n+                                                    \u003C?php echo esc_html(\\WP_STATISTICS\\Admin_Template::unknownToNotSet($item->platform)); ?>\n                                                 \u003C\u002Fspan>\n                                         \u003C\u002Ftd>\n                                         \u003Ctd class=\"wps-pd-l\">","The exploit involves sending an unauthenticated HTTP request to the WordPress site (either to the homepage or the REST API hit endpoint) with a malicious User-Agent header. This payload, which contains JavaScript (e.g., using \u003Cscript> or event handlers like onerror), is parsed by the plugin's device helper and stored in the database. The XSS triggers when an administrator navigates to the 'Browsers', 'Categories', or 'Platforms' report pages in the WP Statistics menu, as the plugin renders the stored agent\u002Fdevice\u002Fplatform string directly into HTML attributes and content without escaping.","gemini-3-flash-preview","2026-06-04 14:50:10","2026-06-04 14:51:46",{"type":42,"vulnerable_version":43,"fixed_version":11,"vulnerable_browse":44,"vulnerable_zip":45,"fixed_browse":46,"fixed_zip":47,"all_tags":48},"plugin","14.16.6","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fwp-statistics\u002Ftags\u002F14.16.6","https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Fwp-statistics.14.16.6.zip","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fwp-statistics\u002Ftags\u002F14.16.7","https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Fwp-statistics.14.16.7.zip","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fwp-statistics\u002Ftags"]