Back to Blog
Vulnerabilities & Exploitation

CVE-2026-87902: Actively Exploited, but Preconditions Decide Your Real Exposure

WordPress core's CVSS 9.2 path traversal drew exploitation attempts within hours of the patch. It is also a case study in why a vulnerable version is not the same as an exploitable one — the route to code execution depends on a site's theme layout and PHP configuration.

PyramidLedger Research6 min read
Share

Key Takeaways

  • CVE-2026-87902 (CVSS 9.2) is an unauthenticated path traversal in WordPress core 4.7.0–7.1.1 that can reach RCE, and it is under active exploitation: Patchstack observed probing within hours of the 22 September patch and CrowdSec tracked tens of thousands of source IPs over the following days. Patch to your branch's fixed release now.
  • A vulnerable version is not automatically an exploitable one. Per the official advisory, the code-execution chain also needs an active theme with a top-level page-* directory and a readable local PHP gadget (the well-known pearcmd.php technique) with PHP's register_argc_argv enabled.
  • Treat those preconditions as a triage tool — which of your sites sit in the demonstrated exploit path — not as a reason to delay patching. A theme swap or host move can flip them, so they are not a control.
  • That combination — per-branch fixes plus environmental preconditions — is why a version-only view misjudges which sites are actually exposed.

WordPress shipped the fix for CVE-2026-87902 on 22 September 2026, and the internet did not wait. Patchstack reported probing attempts within hours of the release, public scanning tooling entered circulation, and CrowdSec observed tens of thousands of unique source IPs sending matching requests in the days that followed — with attackers abusing the pearcmd.php technique to write PHP to disk. If you run WordPress, the first and non-negotiable action is to patch. Everything else in this post is about the second, quieter fact of this CVE: being on a vulnerable version and being in the demonstrated exploit path are not the same thing, and knowing the difference is how you triage a fleet of sites under active attack.

What the vulnerability is

Per the official WordPress advisory (GHSA-7hp8-65ch-5whp, CVSS 9.2, reported by Robert Ressl), an unauthenticated attacker can make get_page_template() page-template resolution include a chosen readable local .php file from outside the active theme directories. The unauthenticated route into that resolution is the URL-decoded pagename request variable, making this a classic local file inclusion — and because WordPress includes the resolved path as PHP, inclusion of a suitable local file becomes code execution.

It affects WordPress 4.7.0 through 7.1.1 and is fixed across every supported branch — 7.1.2, 7.0.6, 6.9.9 and the corresponding point releases all the way back to 4.7.37. One operational consequence of those per-branch backports is that the fixed version is a different point release on each branch, so a bare "is the version below 7.1.2?" comparison mislabels a patched 6.9.9 and misjudges others. The reliable check is that a site is on its branch's fixed release.

Why "critical on every WordPress" needs a caveat

Patchstack, tracking the exploitation, put the nuance plainly: not every vulnerable WordPress installation is immediately exploitable for arbitrary code execution — a site can carry the vulnerable core code while lacking the environment the demonstrated exploit chain requires. The official advisory sets out exactly what that chain needs on top of a vulnerable version.

  • Theme layout. The advisory requires the active child or parent theme to contain a top-level directory whose name starts with page- (for example page-templates), and names the legacy Twenty Twelve and Twenty Fourteen themes along with popular third-party themes such as Neve, Hestia and Sydney. A theme laid out differently does not expose the same resolution path.
  • A local PHP gadget. The advisory notes a chosen local .php file must exist on the server and be readable by the web-server account, and that the well-known pearcmd.php PEAR-to-RCE technique can serve as that file when PHP's register_argc_argv setting is On — the configuration the official php Docker image runs, and the default cPanel setup with PHP before 8.5. As the researcher who reported the flaw puts it, disabling register_argc_argv or removing PEAR breaks this demonstrated route but does not repair WordPress's underlying file-inclusion flaw — so the code-execution leg can be absent on one deployment and present on another, while the inclusion bug, and the need to patch, stay constant.

So the same vulnerable version can mean different things on two sites: one with a page-* theme and a common default PHP build is a live path to code execution, while one with a different theme layout or a genuinely hardened PHP configuration may not complete the demonstrated chain. Because the advisory itself flags the official php Docker image and the default cPanel configuration (PHP before 8.5) as affected, the gadget precondition is common rather than exotic. Neither condition was designed as a security control, which is precisely why you cannot lean on them.

Use the preconditions to triage, not to relax

The value of understanding the preconditions is prioritisation, not permission to wait. Under active mass exploitation, every affected site is patched; the preconditions only tell you which sites to reach first and where the blast radius is widest.

  1. 1Patch every affected install to its branch's fixed release now — this is the fix, and it is being exploited in the wild.
  2. 2Confirm each site is on its branch's fixed release rather than applying a single threshold version, because the fix lands as a different point release on every branch.
  3. 3For triage order, identify sites whose active theme exposes a page-* directory and whose PHP environment enables register_argc_argv or ships PEAR — these sit in the demonstrated exploit path and are the highest priority.
  4. 4Do not treat a missing precondition as protection. A theme change, a plugin that adds page-* templates, or a host migration can move a site into the exploit path without any change to the WordPress version.

The wider lesson for vulnerability scanning

A version match is a weak proxy for exploitability. It over-reports — flagging a critical on sites where the advisory's own preconditions, a page-* theme and a reachable PHP gadget, are not all met — and, because the fix ships as a different point release on each branch, a version-threshold rule also misjudges which sites are even patched. The signal that holds up combines two things the advisory itself points to: whether a site is on its branch's fixed release, and whether the preconditions that make the chain reachable are present. Under a campaign that turned a fresh patch into probing within hours and tens of thousands of scanning IPs within days, that is the difference between a wall of red version-matches and an assessment that tells you which of them an attacker can turn into impact on your specific stack — and in what order to fix them.

Frequently Asked Questions

Are all WordPress sites on an affected version equally exploitable?

No. The path traversal is unauthenticated, but reaching code execution also requires an active theme with a top-level page-* directory and a readable local PHP gadget (the pearcmd.php technique) with register_argc_argv enabled, per the official advisory. Patchstack notes a site can be vulnerable in code yet lack the required theme or PHP environment. Patch regardless — it is under active exploitation.

Does disabling register_argc_argv or removing PEAR protect me?

It can break the common code-execution gadget, but the underlying path traversal and file inclusion remain, and the preconditions can change with a theme or host change. Treat it as defence in depth, not a fix. The fix is upgrading to the patched release for your branch.

How do I confirm I'm patched without a full major upgrade?

The fix was backported to a point release on every supported branch — for example 7.1.2, 7.0.6, 6.9.9 and the relevant 4.x/5.x/6.x releases down to 4.7.37 — so a simple 'below 7.1.2' check is misleading. Confirm each site is on its own branch's fixed release rather than assuming a single threshold version applies.

Sources

  1. 1Unauthenticated path traversal in page-template resolution leading to conditional RCE (GHSA-7hp8-65ch-5whp) — WordPress
  2. 2WordPress 7.1.2 Release — WordPress.org
  3. 3CVE-2026-87902: Attackers Started Probing WordPress Sites Hours After the Patch — Patchstack
  4. 4CVE-2026-87902: 30,000 IPs Target WordPress in Five Days — CrowdSec
  5. 5CVE-2026-87902: Critical WordPress file inclusion and conditional RCE — Robert Ressl (ressl.ch)
Share

Read next