A critical unauthenticated RCE flaw in WordPress core, CVE-2026-87902 (CVSS 9.2), went from patch to active exploitation in a matter of hours. WordPress shipped the fix on September 22, and the first exploitation attempt was logged the same day at 11:49 a.m. UTC. Attackers are chaining the flaw with a well-known PHP gadget, pearcmd.php, to write web shells to disk. If you run WordPress, this is a drop-everything-and-patch situation, and the mechanics are worth understanding because they explain both why the bug is serious and why most sites will survive it.
We monitor and clean WordPress sites at scale, and this is a textbook example of the pattern we see over and over: a core disclosure, a public advisory that hands attackers the recipe, and automated mass-probing before most admins have finished their morning coffee. AgentOffense flagged exactly this compressed timeline as an industry-wide trend in their research on disclosure-to-breach reaction windows, and CVE-2026-87902 is that trend playing out in real time, down to the hour. Here is what the flaw actually does, the classic trick that turns it into code execution, and exactly what to check.
The vulnerability: a file-inclusion bug in template resolution
The flaw lives in how WordPress resolves page templates. Per the WordPress advisory, an unauthenticated attacker can make get_page_template() include a chosen, readable local .php file from outside the active theme directories. In plain terms: a function meant to load a theme’s own template files can be steered into loading an arbitrary PHP file already sitting on the server. That is a local file inclusion (LFI) at the core level, reachable with no login.
What makes CVE-2026-87902 less catastrophic than the CVSS number alone suggests is that it needs two preconditions to line up. Both have to be true:
- Theme condition: the active child or parent theme must contain a top-level directory whose name starts with
page-, for examplepage-templates. This is common but not universal, which is what gates the bug. - Server condition: a chosen local
.phpfile must exist on the server and be readable by the web server account. The attacker’s file of choice is almost alwayspearcmd.php.
An LFI that can only include files already on the server is limited on its own. You cannot upload your own code through it directly. The escalation comes entirely from what you point it at, and that is where pearcmd.php enters.
The pearcmd.php trick: turning file inclusion into code execution
This is the part the news coverage glosses over, and it is the whole game. pearcmd.php is a command-line helper that ships with PEAR, the old PHP package manager, and it lives at a predictable path on many servers: /usr/local/lib/php/pearcmd.php. On a lot of PHP installations it is present by default and readable by the web server, which is exactly the “chosen local .php target” the second precondition calls for.
The reason attackers love pearcmd.php is a long-standing quirk. When a PHP file is included via a web request and the PHP setting register_argc_argv is enabled, the query string gets parsed into argv, as if it were command-line arguments. pearcmd.php reads those arguments and acts on them, including a config-write operation that lets an attacker write attacker-controlled content to an attacker-chosen path. So the chain is: use the WordPress LFI to include pearcmd.php, feed it a query string that behaves like PEAR command-line flags, and have it write a PHP file of your choosing to a writable directory like /tmp or /var/tmp. That written file is a web shell. LFI plus pearcmd.php equals arbitrary file write equals RCE. This is the same gadget that has been abused against countless other LFI bugs for years, which is precisely why exploitation showed up within hours: the second half of the chain was already sitting in every attacker’s toolkit.
The observed attacks match this exactly. Requests include /usr/local/lib/php/pearcmd.php, write a file to /tmp/, and in one variant pull a PHP upload script hosted on GitHub (raw.githubusercontent[.]com/MrG3P5/web-shell/refs/heads/main/uploader.php) to get a full file-upload capability onto the box.
Active exploitation: who and how much
This is not theoretical or slow-moving. Multiple security firms are seeing it live:
- Previdian recorded 68 exploitation attempts against its honeypot network starting September 23, with malicious requests coming from an IP in New Jersey (104.194.9[.]227) and others from an Indonesia-based address.
- Patchstack corroborated the escalation, noting the traffic moved from harmless reconnaissance against core files to active exploitation that includes
pearcmd.phpand writes PHP files to disk.
Previdian’s founder Ryan Dewhurst made a point worth repeating, because it is the silver lining: because WordPress has auto-updates enabled by default, the likely outcome is lots of mass-exploitation attempts but relatively few actual compromises. The sites that get hit are the ones that disabled auto-updates, run outdated versions, or have the specific theme structure the bug requires. That is the population to worry about.
Fix now: the patched versions
WordPress released fixes across every supported branch. Update to at least the patched build on your line:
- 7.1.2 (current branch)
- 7.0.6
- 6.9.9
- 6.8.10
If auto-updates are on and were not disabled, you are most likely already patched, but verify your version rather than assume. If you manage sites for others, check every one of them, because the single site running a pinned old version is exactly the one that gets shelled.
How to check whether you were hit
Patching stops future attempts. It does not remove a web shell an attacker dropped before you updated. Given how fast exploitation started, any site that was on a vulnerable version during September 22 to 24 deserves a look. Hunt for these specific artifacts:
Suspicious PHP files
Check /tmp, /var/tmp, and your web root for attacker-written PHP. Observed file names from the campaign include:
wp-pear-rce-flag.phppoc87902.phpluci_<random>.phpzeta_<random>.php
Any unexplained .php file in a temp directory is a strong signal, since legitimate applications rarely drop executable PHP into /tmp.
Attacker IP addresses
Grep your access logs for these source IPs tied to the malicious activity:
- 104.194.9[.]227 (New Jersey, US)
- 43.250.53[.]42
- 180.251.159[.]243
- 195.178.110[.]247
- 107.189.14[.]87
- 45.61.184[.]170
- 92.246.130[.]76
Request patterns in logs
Look for requests referencing pearcmd.php, requests containing /usr/local/lib/php/, or any request to the site that carries PEAR-style arguments in the query string against a page-template path. Outbound fetches to raw.githubusercontent[.]com/MrG3P5/ are also an indicator of the upload-script stage.
If you find any of this, treat the site as compromised: take it offline or isolate it, preserve logs, remove the dropped files, hunt for persistence (unexpected admin users, modified core files, cron entries, injected code in wp-config.php or theme files), rotate all credentials and salts, and rebuild from a known-clean backup taken before the compromise window if you have one. If you’d rather not run that process solo under time pressure, that exact triage is what our emergency malware removal team handles.
Hardening beyond the patch
Two server-level changes blunt this entire class of attack, not just this CVE:
- Disable
register_argc_argvfor your PHP web SAPI unless you have a specific reason to keep it. With it off, thepearcmd.phptrick loses the mechanism it depends on to parse the query string into arguments. - Remove or restrict pearcmd.php if PEAR is not in use. If
/usr/local/lib/php/pearcmd.phpis not needed, deleting it or making it unreadable to the web server account removes the gadget the second precondition relies on.
Neither replaces patching, but both are cheap defense-in-depth that would have neutralized the RCE half of this chain regardless of the WordPress bug.
The takeaway
CVE-2026-87902 is a clean illustration of how modern WordPress attacks unfold: a core file-inclusion bug, harmless-looking on its own, gets welded to a decade-old PHP gadget that every attacker already carries, and the result is unauthenticated RCE being sprayed at the internet within hours of the patch. Default auto-updates will save most sites. The ones that lose are the unpatched, the pinned, and the unmonitored. Update to 7.1.2, 7.0.6, 6.9.9, or 6.8.10 now, check your temp directories and logs against the indicators above, and if PEAR is dead weight on your server, take pearcmd.php off the board for good. If you want an outside check that your WordPress installs are actually clean and hardened rather than just patched, that is what our penetration testing and website security assessment services are for.
