
WordPress CVE-2026-87902 LFI-to-RCE toolkit with a weaponized exploit chain (PEAR RCE, webshell, admin creation, loot) and a non-intrusive SafeChecker version and risk auditor.

ETHICAL USE ONLY – AUTHORIZED SECURITY TESTING
This repository provides tools for authorized security professionals, blue teams, and penetration testers only.
Unauthorized access to computer systems is illegal under CFAA (US), Computer Misuse Act (UK), TCK 243/244 (Turkey), and similar laws worldwide.
CVE‑2026‑87902 is a critical unauthenticated path traversal and local file inclusion (LFI) vulnerability in WordPress Core (versions 4.7.0 through 7.1.1) that allows an unauthenticated attacker to include arbitrary local .php files via the pagename query parameter, and under specific server conditions escalate to remote code execution (RCE) by chaining the PEAR pearcmd.php file. CVSS score: 9.2 (Critical). Disclosed by Robert Ressl through WordPress's HackerOne program in July 2026. Patched in 7.1.2 on September 22, 2026, with backports down to 4.7 .
The flaw affects every WordPress release since 2016 — a decade of versions that passed code review without detection. The root cause is a single missing validation call in one of the most heavily-traversed code paths in the CMS .
Unsanitized template resolution – get_page_template() in wp-includes/template.php builds template candidates from the pagename query variable. A neighboring code path in the same function applies validate_file() to block ../ sequences, but the $pagename branch does not call it. Any traversal in pagename passes unchecked .
Double-encoded traversal bypass – WordPress applies sanitize_title_for_query() to pagename, which replaces literal dots (.) with hyphens to prevent traversal. But the function operates on already-decoded input and does not recursively decode. An attacker sends %252e%252e%252f; the web server decodes it once to %2e%2e%2f; the sanitizer sees no literal dots and passes it through; then get_page_template() calls urldecode() again inside the function, producing ../ .
Theme directory precondition – The active theme must contain a top-level directory whose name starts with page- (e.g. page-templates/). The constructed filename page-{pagename}.php then escapes the theme root via the traversal. Older default themes (Twenty Twelve, Twenty Fourteen) and popular third-party themes (Neve, Hestia, Sydney) ship this directory. Child themes inheriting from such parents also satisfy the precondition .
LFI sink in locate_template() – The candidate path is passed to locate_template(), which searches the theme directories. Because the traversal resolves to a file outside those directories, and the function checks only file_exists(), any readable .php file is included with full web server privileges. This makes the LFI unconditional on any unpatched site meeting the theme precondition — including wp-config.php with its database credentials and authentication salts .
PEAR pearcmd.php RCE escalation – PEAR ships with many PHP installations. Its pearcmd.php is normally CLI-only, but when register_argc_argv=On, PHP populates $_SERVER['argv'] from the URL query string. The attacker includes pearcmd.php via the LFI, passes config-create as an argument, and supplies PHP code plus an output path (/tmp/shell.php). PEAR writes the attacker's code to disk; a second include executes it .
Second exploitation route – A request combining name (front-page slug), page_id (posts-page ID), preview=true, and a pagename payload diverts WP_Query into its post_name branch, which never rewrites pagename through sanitize_title_for_query(). This allows literal dots in the traversal. Requires a theme without single.php .
Server configuration requirements – RCE depends on two conditions common in real deployments: pearcmd.php present/readable (frequent on shared hosting, cPanel, official PHP Docker images), and register_argc_argv=On (default in PHP below 8.5). PHP 8.5 changed the default to Off. On a modern PHP 8.5+ server without PEAR, exploitation stops at LFI .
The patch – WordPress 7.1.2 adds two layers of defense: (a) the missing validate_file() call in the pagename branch, and (b) a new _wp_is_template_path_allowed() function called by locate_template() for every resolved template. The function rejects paths containing .., then resolves the real path via realpath() and verifies it lies inside one of the allowed theme directories. This defense-in-depth closes the sink, not just one route to it .
Active exploitation in the wild – First malicious requests observed 5 hours after patch release (17:44 UTC, Sept 22, 2026). Traffic increased tenfold over the next day. Three stages observed: config-show reconnaissance → core-file detection → config-create weaponization. Payload filenames included wp-pear-rce-flag.php, poc87902.php, luci_*.php, zeta_*.php, written to /tmp and /var/tmp. Attacking IPs: 169.58.48.193, 169.58.48.195, 2001:df1:e8c0::106b .
Impact – Code execution with web server privileges. Full site takeover, wp-config.php credential theft, data exfiltration, webshell installation, admin user creation, reverse shell, supply-chain attacks via modified plugins/themes, and lateral movement into connected services. The CVSS 9.2 score reflects network-exploitable, no-auth, high-confidentiality/integrity/availability impact. The high attack complexity reflects the theme and server preconditions, but on typical shared hosting those conditions are frequently met.
page-* directory in the active theme, set register_argc_argv=Off in php.ini, and block double-encoded traversal in the pagename parameter at the WAF level.