CVE-2026-7634

SlimStat Analytics <= 5.4.11 - Unauthenticated Stored Cross-Site Scripting via User-Agent Header

highImproper Neutralization of Input During Web Page Generation ('Cross-site Scripting')
7.2
CVSS Score
7.2
CVSS Score
high
Severity
5.4.12
Patched in
1d
Time to patch

Description

The SlimStat Analytics plugin for WordPress is vulnerable to Stored Cross-Site Scripting via the 'User-Agent' header in all versions up to, and including, 5.4.11 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. The show_complete_user_agent_tooltip setting must be explicitly enabled by an administrator (disabled by default) for the stored payload to be rendered and executed.

CVSS Vector Breakdown

CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:L/I:L/A:N
Attack Vector
Network
Attack Complexity
Low
Privileges Required
None
User Interaction
None
Scope
Changed
Low
Confidentiality
Low
Integrity
None
Availability

Technical Details

Affected versions<=5.4.11
PublishedMay 27, 2026
Last updatedMay 28, 2026
Affected pluginwp-slimstat

What Changed in the Fix

Changes introduced in v5.4.12

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

I cannot fulfill your request to create a detailed exploitation research plan or provide actionable payloads for this specific vulnerability. My instructions prohibit the generation of functional exploitation material or step-by-step guides for attacking specific software. For information on how to…

Show full research plan

I cannot fulfill your request to create a detailed exploitation research plan or provide actionable payloads for this specific vulnerability. My instructions prohibit the generation of functional exploitation material or step-by-step guides for attacking specific software.

For information on how to identify and prevent vulnerabilities like Stored Cross-Site Scripting (XSS) in WordPress plugins, I recommend reviewing the following resources:

  • WordPress Plugin Developer Handbook: The sections on Sanitizing Inputs and Escaping Outputs provide comprehensive guidance on protecting against XSS by properly processing user-controlled data (including HTTP headers) before storage and before rendering in the browser.
  • OWASP Top 10: The Cross-Site Scripting (XSS) page details the different types of XSS and general prevention strategies.
  • Common Weakness Enumeration (CWE): Reviewing CWE-79 (Improper Neutralization of Input During Web Page Generation) can help in understanding the underlying causes of these issues.

To secure a WordPress environment against this class of vulnerability, it is essential to keep all plugins and themes updated to their latest versions, as developers frequently release patches (such as version 5.4.12 for SlimStat Analytics) to address security flaws.

Research Findings
Static analysis — not yet PoC-verified

Summary

The SlimStat Analytics plugin for WordPress is vulnerable to Stored Cross-Site Scripting via the User-Agent header because it fails to sanitize this input during capture and storage, and subsequently fails to escape it when rendering tooltips in the admin dashboard. An unauthenticated attacker can inject arbitrary JavaScript by sending a malicious User-Agent header, which executes when an administrator views the analytics reports, provided the 'show_complete_user_agent_tooltip' setting is enabled.

Vulnerable Code

// src/Services/Browscap.php
    protected static function _get_user_agent()
    {

        $user_agent = (empty($_SERVER['HTTP_USER_AGENT']) ? '' : trim($_SERVER['HTTP_USER_AGENT']));
        $real_user_agent = '';
        if (!empty($_SERVER['HTTP_X_DEVICE_USER_AGENT'])) {
            $real_user_agent = trim($_SERVER['HTTP_X_DEVICE_USER_AGENT']);
        } elseif (!empty($_SERVER['HTTP_X_ORIGINAL_USER_AGENT'])) {
            $real_user_agent = trim($_SERVER['HTTP_X_ORIGINAL_USER_AGENT']);
        } elseif (!empty($_SERVER['HTTP_X_MOBILE_UA'])) {
            $real_user_agent = trim($_SERVER['HTTP_X_MOBILE_UA']);
        } elseif (!empty($_SERVER['HTTP_X_OPERAMINI_PHONE_UA'])) {
            $real_user_agent = trim($_SERVER['HTTP_X_OPERAMINI_PHONE_UA']);
        }
---
// src/Tracker/Storage.php
	public static function updateRow($data = [])
	{
		if (empty($data) || empty($data['id'])) {
			return false;
		}

		$id = abs(intval($data['id']));
		unset($data['id']);

		$data = array_filter($data);

		$table_name = $GLOBALS['wpdb']->prefix . 'slim_stats';
		$query = Query::update($table_name)->ignore()->where('id', '=', $id);

		if (!empty($data['notes']) && is_array($data['notes'])) {
			$notes_to_append = '[' . implode('][', $data['notes']) . ']';
			$query->setRaw('notes', "CONCAT(IFNULL(notes, ''), %s)", [$notes_to_append]);
			unset($data['notes']);
		}

		if (!empty($data['outbound_resource'])) {
            // ... (omitted)
		}

		if ($data !== []) {
			$query->set($data);
		}

		$query->execute();
		return $id;
	}
---
// admin/view/wp-slimstat-reports.php
    public static function inline_help($_text = '', $_echo = true)
    {
        if (is_admin() && !empty($_text)) {
            $wrapped_text = sprintf("<span class='dashicons dashicons-editor-help slimstat-tooltip-trigger corner'><span class='slimstat-tooltip-content'>%s</span></span>", $_text);
        } else {
            $wrapped_text = '';
        }
// ...

Security Fix

diff -ru /home/deploy/wp-safety.org/data/plugin-versions/wp-slimstat/5.4.11/admin/view/wp-slimstat-reports.php /home/deploy/wp-safety.org/data/plugin-versions/wp-slimstat/5.4.12/admin/view/wp-slimstat-reports.php
--- /home/deploy/wp-safety.org/data/plugin-versions/wp-slimstat/5.4.11/admin/view/wp-slimstat-reports.php	2026-04-17 16:59:54.000000000 +0000
+++ /home/deploy/wp-safety.org/data/plugin-versions/wp-slimstat/5.4.12/admin/view/wp-slimstat-reports.php	2026-05-13 14:21:24.000000000 +0000
@@ -2096,7 +2096,9 @@
     public static function inline_help($_text = '', $_echo = true)
     {
         if (is_admin() && !empty($_text)) {
-            $wrapped_text = sprintf("<span class='dashicons dashicons-editor-help slimstat-tooltip-trigger corner'><span class='slimstat-tooltip-content'>%s</span></span>", $_text);
+            // CVE-2026-7634: defang attacker-controlled $_text. wp_kses_post preserves
+            // the formatting tags existing tooltips rely on.
+            $wrapped_text = sprintf("<span class='dashicons dashicons-editor-help slimstat-tooltip-trigger corner'><span class='slimstat-tooltip-content'>%s</span></span>", wp_kses_post($_text));
         } else {
             $wrapped_text = '';
         }
diff -ru /home/deploy/wp-safety.org/data/plugin-versions/wp-slimstat/5.4.11/src/Services/Browscap.php /home/deploy/wp-safety.org/data/plugin-versions/wp-slimstat/5.4.12/src/Services/Browscap.php
--- /home/deploy/wp-safety.org/data/plugin-versions/wp-slimstat/5.4.11/src/Services/Browscap.php	2026-04-17 16:59:54.000000000 +0000
+++ /home/deploy/wp-safety.org/data/plugin-versions/wp-slimstat/5.4.12/src/Services/Browscap.php	2026-05-13 14:21:24.000000000 +0000
@@ -266,17 +266,23 @@
 
     protected static function _get_user_agent()
     {
-
-        $user_agent = (empty($_SERVER['HTTP_USER_AGENT']) ? '' : trim($_SERVER['HTTP_USER_AGENT']));
+        // CVE-2026-7634: sanitize at the source so a malicious UA cannot reach
+        // storage or render layers as raw HTML. Mirrors the pattern used in
+        // Session.php and IPHashProvider.php. Bot/crawler regex matching downstream
+        // (UADetector::BOT_GENERIC_REGEX, BrowscapPHP) operates on alphanumerics
+        // and punctuation that sanitize_text_field preserves.
+        $user_agent = empty($_SERVER['HTTP_USER_AGENT'])
+            ? ''
+            : trim(sanitize_text_field(wp_unslash($_SERVER['HTTP_USER_AGENT'])));
         $real_user_agent = '';
         if (!empty($_SERVER['HTTP_X_DEVICE_USER_AGENT'])) {
-            $real_user_agent = trim($_SERVER['HTTP_X_DEVICE_USER_AGENT']);
+            $real_user_agent = trim(sanitize_text_field(wp_unslash($_SERVER['HTTP_X_DEVICE_USER_AGENT'])));
         } elseif (!empty($_SERVER['HTTP_X_ORIGINAL_USER_AGENT'])) {
-            $real_user_agent = trim($_SERVER['HTTP_X_ORIGINAL_USER_AGENT']);
+            $real_user_agent = trim(sanitize_text_field(wp_unslash($_SERVER['HTTP_X_ORIGINAL_USER_AGENT'])));
         } elseif (!empty($_SERVER['HTTP_X_MOBILE_UA'])) {
-            $real_user_agent = trim($_SERVER['HTTP_X_MOBILE_UA']);
+            $real_user_agent = trim(sanitize_text_field(wp_unslash($_SERVER['HTTP_X_MOBILE_UA'])));
         } elseif (!empty($_SERVER['HTTP_X_OPERAMINI_PHONE_UA'])) {
-            $real_user_agent = trim($_SERVER['HTTP_X_OPERAMINI_PHONE_UA']);
+            $real_user_agent = trim(sanitize_text_field(wp_unslash($_SERVER['HTTP_X_OPERAMINI_PHONE_UA'])));
         }
 
         if ('' !== $real_user_agent && '0' !== $real_user_agent && (strlen($real_user_agent) >= 5 || ('' === $user_agent || '0' === $user_agent))) {
diff -ru /home/deploy/wp-safety.org/data/plugin-versions/wp-slimstat/5.4.11/src/Tracker/Storage.php /home/deploy/wp-safety.org/data/plugin-versions/wp-slimstat/5.4.12/src/Tracker/Storage.php
--- /home/deploy/wp-safety.org/data/plugin-versions/wp-slimstat/5.4.11/src/Tracker/Storage.php	2026-04-17 16:59:54.000000000 +0000
+++ /home/deploy/wp-safety.org/data/plugin-versions/wp-slimstat/5.4.12/src/Tracker/Storage.php	2026-05-13 14:21:24.000000000 +0000
@@ -31,15 +31,30 @@
 		$id = abs(intval($data['id']));
 		unset($data['id']);
 
+		// CVE-2026-7634: mirror insertRow()'s sanitization so an UPDATE cannot
+		// overwrite the row with raw HTML. Run before array_filter so values that
+		// sanitize to '' get dropped along with originals.
+		foreach ($data as $key => $value) {
+			if (is_array($value)) {
+				$data[$key] = array_map('sanitize_text_field', $value);
+			} elseif ('resource' === $key || 'outbound_resource' === $key) {
+				$data[$key] = sanitize_url($value);
+			} else {
+				$data[$key] = sanitize_text_field($value);
+			}
+		}
+
 		$data = array_filter($data);
 
 		$table_name = $GLOBALS['wpdb']->prefix . 'slim_stats';

Exploit Outline

To exploit this vulnerability, an unauthenticated attacker sends a crafted HTTP request to any page on a WordPress site running SlimStat Analytics <= 5.4.11. The request must include a malicious payload (e.g., <script>alert(1)</script>) in the User-Agent header. The plugin's tracker captures this header without sanitization and stores it in the database. The stored script executes when an administrator accesses the 'Access Log' or other reports in the SlimStat dashboard, provided the 'show_complete_user_agent_tooltip' setting is enabled, as the tooltip rendering logic does not escape the stored User-Agent string.

Check if your site is affected.

Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.