WordPress CVE-2026-87902: Unauthenticated LFI to RCE in 4.7โ€“7.1.1

WordPress CVE-2026-87902 chains unauthenticated LFI to RCE across all versions before 7.1.2. Patch now and secure your installation.

Introduction

WordPress CVE-2026-87902 is not a vulnerability you can shrug off until the next maintenance window. It touches every WordPress installation from version 4.7 onward, requires no authentication, and chains a local file inclusion directly into remote code execution under common server configurations. The moment I read the advisory, I thought about the hosting environment I managed back in 2019, where a single unpatched plugin left a client’s site wide open to file reads. This one is worse because it lives in core and the attack surface is not a misconfigured theme or a forgotten update. It is the template loader itself.

The CVSS score of 9.2 and the CWE-98 classification tell part of the story, but the real weight comes from what the fix reveals. WordPress 7.1.2 landed on September 22, 2026 as a security-only release with a single patch, which is unusual and signals severity. The vulnerability was reported by Robert Ressl, and Patchstack customers were already shielded through RapidMitigate rules before the public fix existed. That sequence matters because it means the exploit path was known to researchers and mitigations were in place while the wider ecosystem remained exposed.

Every WordPress install running anything before 7.1.2 is vulnerable. If your site has automatic background updates disabled, it will stay vulnerable until you apply the patch manually. If you are on a managed host, confirm with your provider whether they have applied mitigation rules yet. The honest framing is a conditional chain: unauthenticated file inclusion always, code execution when the host happens to line up. Plenty of hosts line up, especially cPanel environments below PHP 8.5 and official PHP Docker images where register_argc_argv stays enabled by default. Treat this as critical unless you have checked your own stack and know otherwise.

A site owner once told me their WordPress install had been running for six years without a major upgrade, and they assumed the default themes kept them safe. The page-* template resolution branch does not care about your assumptions. It reads the pagename query variable straight from the request, appends .php, and hands the path to the template loader without a validate_file() guard. The sibling branch above it already had the check three lines earlier. The protection existed three lines above the place it was missing. That pattern shows how easy it is to overlook a missing guard when the same validation exists nearby.

If you are reading this on a host that has not yet applied the patch, update to WordPress 7.1.2 now. If you cannot patch immediately, check whether your active theme carries a page-* top-level directory and rename or remove it as a defensive step. Confirm with your hosting provider whether register_argc_argv is enabled on your stack. The vulnerability demands action today rather than at the next scheduled maintenance window.

What is WordPress CVE-2026-87902?

WordPress CVE-2026-87902 is an unauthenticated local file inclusion flaw in page template resolution that can escalate to remote code execution. The vulnerability sits deep in WordPress core, which means it is not something you can patch by updating a plugin or theme. It lives in wp-includes/template.php, the file that decides which template gets loaded when a visitor hits your site.

Patchstack has assigned this issue a CVSS 4.0 score of 9.2 and classified it under CWE-98, which covers improper control of filename for an include statement. The score reflects the severity accurately. An attacker does not need credentials, does not need to interact with any form on your site, and does not need to exploit a poorly configured plugin. They just need your URL.

The affected range runs from WordPress 4.7.0 through 7.1.1. That is nearly a decade of releases, which is unusually broad for a single vulnerability of this type. Most security issues affect only the most recent versions or a narrow window of upgrades. This one touches every installation that has not moved past 7.1.1, regardless of when it was originally set up.

No login or user account is required to trigger the bug. The vulnerability exploits the way WordPress resolves the pagename query variable from the incoming request. When you request your-site.com/page/something, WordPress takes that something value, appends .php to it, and includes the resulting path as a template file. There is no validation step stopping directory traversal characters from reaching the filesystem.

The practical impact depends on what files exist on your server. File inclusion alone does not automatically mean code execution. You need a specific condition to line up, usually PEAR’s pearcmd.php being accessible and register_argc_argv being enabled. But even without RCE, unauthenticated local file inclusion is serious enough to warrant immediate action. An attacker who can read arbitrary files on your server can pull configuration files, database credentials, or sensitive theme data.

Every site running WordPress before 7.1.2 falls into the danger zone. The scope makes this vulnerability harder to ignore than the typical core bug that only affects edge cases or rarely used features.

When did this come to light?

Robert Ressl reported the vulnerability to WordPress, and the patch landed in version 7.1.2 on September 22, 2026 (Patchstack article (opens in new tab)). The release was flagged as a security-only update, which means WordPress shipped that version with a single fix rather than bundling it into a routine maintenance drop. That pattern rarely appears unless the issue is severe enough to warrant breaking the normal update cadence.

Before the public patch went live, Patchstack had already deployed RapidMitigate rules for its customers. This is standard practice for their service. Runtime protection rules sit in front of the application and block exploit requests before they reach vulnerable code, buying time while site operators work through their own update processes. It is worth understanding that these rules are a stopgap, not a fix. If the underlying vulnerability remains in your WordPress installation, you are relying on a filter that can break, get misconfigured, or miss an edge case.

The same CVE identifier, CVE-2026-87902, and the GitHub Security Advisory GHSA-7hp8-65ch-5whp were published on the same day as the release. This tight timeline between disclosure, patching, and public advisories is worth noting because it means the window between discovery and exploitation was narrow. Researchers who were tracking the issue would have seen the patch land almost immediately and could begin analyzing the fix for bypasses.

Patchstack added the vulnerability to their database on the day of the release. Their RapidMitigate rule went live alongside the advisory, which gives hosted customers immediate protection without requiring manual intervention. If you are on a managed WordPress host, there is a good chance your provider has either already applied this rule or pushed the 7.1.2 update to your site. You should verify this with them rather than assume.

What makes the timeline particularly relevant to operators is the gap between the report date and the public disclosure. There is almost always a period where the vulnerability exists in the wild but remains unpatched. During that window, automated scanners and opportunistic attackers begin probing for the flaw. The severity of this issue, combined with its broad affected range, means any site running an unpatched version of WordPress is exposed to active exploitation attempts right now.

{
$templates[] = $template;
}
if ( $pagename ) {
$pagename_decoded = urldecode( $pagename );
if ( $pagename_decoded !== $pagename ) {
$templates[] = “page-{$pagename_decoded}.php”;
}
$templates[] = “page-{$pagename}.php”;
}


The first branch runs `validate_file()` before accepting a template path. The second branch, built from `pagename`, does not. The protection existed literally three lines above the hole. It is not a subtle oversight. It is a gap you can see the moment you look at the two blocks side by side.

The filename is assembled as `"page-{$pagename}

## Can you actually get RCE from this?

Here is where people tend to skip ahead and declare "arbitrary code execution" without reading the fine print. I get it. A CVSS of 9.2 does not leave room for hedging. But the technical reality is more layered, and the distinction matters when you are explaining to a client or your hosting provider why this deserves a page one incident response rather than a ticket in next week's maintenance window.

Inclusion of a local `.php` file is not the same as running code of your choosing. When WordPress includes a file through this flaw, it executes whatever that file does. That is a meaningful gap. Getting from "I included a file" to "I have a shell" requires the included file to behave usefully when executed, and in the WordPress ecosystem the standard candidate is PEAR's `pearcmd.php`. This is a real file that ships with PHP installations on many servers. It has been abused for years as an LFI-to-RCE primitive, and it shows up again here for the same reason it showed up everywhere else: it accepts command-line arguments and forwards them to PHP when the right setting is active.

That setting is `register_argc_argv`, and this is the part that should keep you up at night. The official PHP Docker images ship with it enabled by default. cPanel environments running PHP versions below 8.5 also have it enabled by default. If you run WordPress inside a container, which a lot of modern stacks do, you are almost certainly in the affected set. If you host WordPress on cPanel, which a significant chunk of the small business web happens to run on, the condition is again met out of the box. Telling a customer "your server configuration is unusual" about this is no longer accurate. The default behavior of popular hosting platforms aligns with the exploit requirement.

So the honest framing is conditional but sharp. Unauthenticated file inclusion is guaranteed on any vulnerable site running the affected WordPress version. Code execution follows when the host's PHP configuration lines up. That second condition is true for enough environments that treating this as critical is not paranoia. It is operational reality.

I have had to tell clients this before: the vulnerability is real regardless of whether the RCE chain works on their specific box. The file inclusion itself is dangerous. It exposes sensitive files, it allows arbitrary reads within the filesystem boundary, and in practice the RCE path opens on a large share of deployments. When I see a site still running WordPress 7.1.0 or earlier, I do not ask whether `register_argc_argv` is on. I start the patch process immediately and verify the configuration afterward.

If you want to check your own stack in under thirty seconds, run this on your server.

```bash
php -i | grep register_argc_argv

If the output says On, the full RCE chain is possible on that host. If it says Off, the inclusion flaw remains but the code execution path is blocked. Either way, the site is vulnerable and needs updating. The two facts are not interchangeable, but both demand the same urgency.

What did WordPress change in 7.1.2?

WordPress shipped two changes in this release, and understanding both matters more than reading the advisory alone.

The first fix is surgical. It closes the specific bypass by applying the same validate_file() check that the sibling branch above it already had:

// wp-includes/template.php, WordPress 7.1.2
if ( $pagename_decoded !== $pagename && 0 === validate_file( $pagename_decoded ) ) {
    $templates[] = "page-{$pagename_decoded}.php";
}

Before this, urldecode() could turn a safe-looking slug like page-%2e%2e%2fetc%2fpasswd into an actual traversal path with no guard in place. The decoder now runs through the same validation filter that was already protecting the other branch three lines above it. This alone would have stopped the reported exploit.

The second fix is what makes me trust this release more than a typical security patch. WordPress 7.1.2 introduces a containment check that every resolved template path must now pass, regardless of which code path produced it:

// wp-includes/template.php, new in WordPress 7.1.2
function _wp_is_template_path_allowed( $path ) {
    global $wp_stylesheet_path, $wp_template_path;
    if ( 0 === preg_match( '#(?:^|/)\.\.[. ]*(?:/|$)#', wp_normalize_path( $path ) ) ) {
        return true;
    }
    $real_path = realpath( $path );
    // ...
}

This function resolves the real filesystem path and requires it to sit inside an allowed theme directory. A file path that exists and contains no .. components is allowed immediately. Anything else gets resolved and checked against wp_stylesheet_path, wp_template_path, or theme-compat.

That second change says something the advisory does not spell out. A one-line validation fix would have been enough for the reported issue. Adding a check that every template path must resolve inside the stylesheet directory, the template directory, or theme-compat means the security team treated template resolution as a class of problem rather than a single bug. They were clearly not confident the reported path was the only one. That is the right call, and it raises the bar for any similar future bypasses in this area.

I expect this containment layer will close off several attack surfaces that researchers are already circling. It does not make WordPress invulnerable, but it turns a narrow hole into a much harder problem to solve.

Is my site vulnerable?

I have spent too many years watching operators scroll through security advisories wondering whether they are actually in the danger zone. This one is easy to check, and the answers matter before you do anything else.

What version am I running? Log into your WordPress dashboard and look at the version number, or run wp core version from the command line if you have WP-CLI installed. Anything before 7.1.2 is exposed. I do not know how many sites are still sitting on older releases, but the affected range runs from 4.7.0 all the way up to 7.1.1, which means nearly every active install out there for the last several years is in scope. If you are not sure what version you are running, assume the worst and verify.

Do I have a theme with a page-* top-level directory? This is the part most people miss. The vulnerability needs a directory that starts with page- in your theme folder for the path traversal to land anywhere useful. Run ls -d wp-content/themes/your-active-theme/page-* to check. Twenty Twelve, Twenty Thirteen, and several third-party themes shipped with a page-templates directory by default. It is a perfectly normal thing to have on an old install, and it is exactly the precondition this exploit relies on. If you find one, rename it or move it out of the way as a defensive step. The path must begin with page-, so a directory called page-templates is all an attacker needs.

Is register_argc_argv enabled on my server? Run php -i | grep register_argc_argv on your host. If it says On, the RCE chain is possible. If it says Off, you are still vulnerable to file inclusion, which is bad enough, but the code execution part will not fire. Official PHP Docker images and cPanel environments running PHP below 8.5 have this setting enabled by default, which makes it common rather than unusual. I have seen it toggled off on hardened setups, but most default installations leave it alone.

Am I on a managed host? Some hosting providers have already pushed mitigation rules through Patchstack RapidMitigate or applied their own WAF signatures. Contact your provider and ask whether they have mitigated CVE-2026-87902 specifically. Do not accept a vague yes. Ask them to name the rule or the patch. A runtime rule is not the same thing as the actual fix, and you should know which one you are relying on.

What should I do today?

Update WordPress immediately if you are not already on version 7.1.2. The core update is the only thing that fully closes the hole, and it is straightforward to apply. Log into your dashboard and navigate to the Updates screen. If you have automatic background updates enabled, your site may already be patched, but you should verify the version number rather than assume. Sites running on older PHP versions or on managed hosting where you do not control the WordPress core should check with their provider first.

I would still run a quick theme audit even after you patch. Look at your active theme directory for any folder starting with page- and rename or remove it. It is the kind of thing that sits quietly on a server and waits. A directory called page-templates is harmless in normal operation, but it is exactly the precondition this vulnerability needs. Running ls -d wp-content/themes/your-active-theme/page-* takes thirty seconds and tells you whether your theme ships with one.

Hosting operators should also audit register_argc_argv across their stacks. Run php -i | grep register_argc_argv in your PHP environment and check whether it returns On. If it does, and you are running PHP below 8.5, the RCE chain becomes viable. I have disabled this setting on hardened PHP builds without breaking production traffic, but it requires testing on your own stack first. Do not toggle it blindly across hundreds of accounts.

If you cannot update right away, Patchstack offers a RapidMitigate rule that shields customers from exploitation before the patch lands. Use it as a stopgap, not as a permanent solution. Runtime rules catch specific patterns. They do not fix broken code paths in template resolution. The source advisory from Patchstack confirms they deployed this protection quickly, but their guidance remains clear: update to 7.1.2 as soon as you can.

The most practical action you can take right now is opening your WordPress dashboard and checking your version. That one step tells you whether you are exposed or already protected.

What Comes Next for This Vulnerability

The _wp_is_template_path_allowed() containment check introduced in 7.1.2 raises the bar for any follow-up exploits in this same area. I do not know how this holds up against determined researchers who specialize in template resolution, but the security team clearly treated this as a class of problem rather than a single bug. That is a stronger defensive posture than a one-line validation fix would have been. Still, nothing in software security is permanent. Template resolution touches a lot of WordPress internals, and edge cases tend to surface over time.

I expect researchers to keep probing template-related code paths across all supported branches. There is a natural rhythm to these things. A critical vulnerability like this one attracts attention, patches land, and then people look for the next variation that might slip through. The new containment check makes the simple page-templates traversal attack pattern much harder to reproduce, but that does not mean template resolution is now bulletproof. It means the easiest path is closed.

WordPress will likely backport the fix to any currently supported older branches. The Patchstack advisory notes that 7.1.2 was released with backported fixes for every supported branch down to 4.7, but the source material does not confirm whether branches beyond 7.1 still receive active security updates. If you are running something older than 7.1, verify with WordPress.org which branches are currently supported before assuming you are covered by a backport.

Unpatched installs in the 4.7 through 7.1.1 range remain the primary attack surface while awareness grows. Automated scanners pick up on vulnerabilities quickly, and I have seen similar patterns play out before where mass exploitation follows within days of a public disclosure. The window between announcement and patching is where most damage happens. If your site is still running anything before 7.1.2, treat that as an active exposure rather than a theoretical risk.

Check your version from the dashboard right now. If it is not 7.1.2 or later, apply the update today instead of waiting for a maintenance window.