CVE-2026-119977: Inside the WordPress Upgrade-Window Race and the Predictable Staging Flaw
In late October 2026, WordPress Core shipped a fix for CVE-2026-119977 — an unauthenticated remote code execution (RCE) that exists only while a site is updating itself. It affects WordPress 4.7.0 through 7.1.3, a range that covers the majority of self-hosted installations on the internet, and it was added to CISA’s Known Exploited Vulnerabilities catalog within days of disclosure.
The flaw is not in a plugin, a theme, or a request handler. It is in the core upgrade process itself. When WordPress performs a full-package core update, it extracts the new release into a staging directory under the web root. On affected versions that directory is created at a predictable, web-accessible path, and the PHP staged inside it executes in the server’s context.
That turns a routine maintenance action into an exposure window. For a few seconds, an unauthenticated attacker who can reach the site over HTTP and who knows the predictable path can execute code on the server.
The question is not whether you run a vulnerable version. It is whether an attacker can reach your site during the seconds it spends upgrading.
Vulnerability At a Glance
| Field | Value |
| CVE ID | CVE-2026-119977 |
| Component | WordPress Core (full-package core upgrader) |
| CWE | CWE-367 — Time-of-Check to Time-of-Use (TOCTOU) race condition (inferred from the race-condition root cause; not stated on NVD at time of writing) |
| CVSS v3.1 | 8.1 (High) — CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H (no CVSS v4.0 published) |
| Prerequisites | A full-package core upgrade in progress and HTTP reachability during that window. AC:H reflects that exploitation means winning the race. |
| Impact | Unauthenticated remote code execution in the web-server context |
| Affected versions | 4.7.0 – 7.1.3 |
| Fixed version | 7.1.4 |
| Exploitation status | On CISA KEV (reported actively exploited). Our lab proves server-side execution at the predictable staging path; reliable exploitation in the wild depends on winning the brief upgrade-window race. |
What actually breaks
A full-package core upgrade is a file operation. WordPress downloads the new release as a zip, extracts it into a staging area under wp-content/upgrade/, then copies the files into place and removes the staging area. The vulnerability lives in the gap between extract and cleanup.
On affected versions, the staging directory is named predictably — an attacker can guess the path without any information from the server. Because it sits under the web root and the web server executes PHP anywhere beneath it, any PHP file present in that directory during the window is reachable and runnable by an unauthenticated request.
The staging directory is trusted by the filesystem but exposed to the web. That is the whole bug: a predictable name, a web-accessible location, and a brief moment where executable code lives there.
Core upgrade starts
│
▼
Extract new core ──► wp-content/upgrade/wordpress/ (PREDICTABLE, web-accessible)
│ │
│ ├──► attacker requests the predictable path ◄── RACE
▼ │
Copy into place └──► PHP executes in server context ──► RCE
│
▼
Cleanup (window closes)
The fix in 7.1.4 removes the predictability: the staging path is randomized, so an attacker can no longer guess where the extracted code lives during the window.
Impact: From a Predictable Path to Code Execution
The severity escalates in three stages, from simply observing the staging area to executing arbitrary commands through it.
Predictable Staging-Path Exposure
At the lowest tier, the staging path is knowable. An attacker does not need to leak it, brute-force it, or authenticate — the directory name is fixed by the upgrade code. That predictability is the precondition for everything above it, and it is exactly what the patch removes.
In the lab, the contrast is clean: the identical unauthenticated request succeeds against the vulnerable build and fails against the patched build, because the patched build no longer stages code at a path the attacker can name.

Figure 1: The same unauthenticated request against both builds. On 7.1.3 (vulnerable) the predictable staging path executes and impact is proven; on 7.1.4 (patched) the randomized path cannot be reached and the attack fails.
Staged-File Execution During the Window
In the middle tier, the attacker does more than observe — they reach PHP that the server will execute. While the upgrade window is open, requests to the predictable path are served and run, rather than returned as inert text or blocked. This is the step that converts a predictable location into a code path.
Upgrade window open ──► GET /wp-content/upgrade/wordpress/.php
│
▼
server executes PHP (not source disclosure)
Unauthenticated Remote Code Execution
At the top tier, execution in the web-server context is full RCE. In the lab the staged PHP runs an attacker-supplied command and returns its output — proving genuine server-side execution, not a version banner or a scanner match. The command runs as the web user (www-data), which is enough to read application secrets, write web shells, pivot to the database, and establish persistence.

Figure 2: Arbitrary command execution on the vulnerable target during the upgrade window. The server returns the evaluated output of the attacker’s command — a unique marker followed by `uid=33(www-data)` and the container hostname — confirming code execution rather than source disclosure.
Why RCE During an Upgrade Matters Beyond the Web Process
Code execution as the web user is rarely the end state. From www-data, an attacker reads wp-config.php and the database credentials it holds, writes a persistent web shell outside the staging directory so it survives the upgrade, and reaches any internal service the web host can see.
The upgrade window closes; the web shell does not. Because the staged code executes before cleanup, an attacker who wins the race can drop persistence that long outlives the few seconds of exposure. The blast radius is the whole site and whatever the web host is trusted to reach — not just the moment of the update.
Attack Scenarios
The exposure appears in two directions, and the second is the dangerous one because no human is watching.
Scenario 1: Attacker Races an Operator-Initiated Update
Admin clicks "Update now" ──► core extracts to predictable path
│
Attacker (polling the site) ───────────┘──► hits the window ──► RCE
An attacker who can see that a site is about to update — or who simply polls the predictable path continuously — races the operator. The attacker needs no credentials and no interaction from the operator beyond the update they already intended to perform.
Scenario 2: Background Auto-Update Opens the Window Unattended
Scheduled/background auto-update fires ──► predictable path appears
│
Attacker polling continuously ──────────────────────┘──► RCE, with no operator present
WordPress’s automatic background updates open the same window with no administrator online to notice anomalies. A continuously polling attacker converts routine, unattended maintenance into an unmonitored code-execution opportunity. This is the scenario that makes mass, opportunistic exploitation viable.
Impact Beyond a Single Site
The flaw is single-product, but its reach is shaped by how WordPress is operated at scale.
| Deployment context | Why exposure compounds |
| Automatic background updates enabled | The window opens unattended and predictably, ideal for opportunistic polling. |
| Managed/shared WordPress hosting | Fleet-wide update schedules create many simultaneous windows across tenants. |
| Multisite networks | A single core upgrade exposes every site in the network at once. |
| Agency / reseller fleets | Centrally scheduled updates synchronize the windows an attacker can target. |
How Enterprises Should Respond
Patching closes the flaw. The remaining controls shrink the window and the predictability that make it exploitable, and give you a way to detect attempts.
1. Patch first
Update WordPress Core to 7.1.4 or later on every site, including those managed by agencies or hosting providers. The fix randomizes the staging path and is the only control that removes the root cause rather than narrowing the window. Inventory every install — self-hosted, multisite, and third-party-managed — because an unpatched site anywhere in the estate is exploitable during its next update.
2. Restrict the upgrade window
Perform core upgrades inside a controlled maintenance window with public access to wp-admin and wp-content/upgrade/ temporarily restricted (IP allow-list or maintenance mode). An update that no unauthenticated client can reach cannot be raced. (Partial: it protects operator-initiated updates, not unattended background ones — see control 4.)
3. Block web access to the staging directory
Add a web-server rule that denies direct HTTP requests to wp-content/upgrade/ outright. In Apache, deny the path in the vhost or an .htaccess; in Nginx, location ^~ /wp-content/upgrade/ { deny all; }. The staging area is only ever used server-side, so blocking it externally has no functional cost and removes the web-accessible half of the flaw.
4. Govern automatic background updates
On internet-facing sites still on an affected version, disable or gate unattended background core updates so the window never opens without oversight, or pin updates to the restricted maintenance window above. This directly addresses Scenario 2, where no operator is present to notice exploitation.
5. Reduce post-exploitation privilege
Run PHP as a non-root, least-privilege web user (the lab’s www-data), make the WordPress filesystem read-only except for the paths that genuinely need writes, and give the database account only the grants the site requires. None of this stops the race, but it limits what a won race yields and how far it spreads.
6. Hunt for staging and execution signals
After any update, check for unexpected PHP files in wp-content/upgrade/ and elsewhere under wp-content/. In access logs, look for requests to /wp-content/upgrade/* — especially repeated or automated hits around update times. Watch for new administrator accounts, unexpected outbound connections from the web user, and web shells written outside the staging directory.
Closing: The Version Is the Flaw, the Window Is the Risk
CVE-2026-119977 is a reminder that a vulnerability does not have to live in a request handler to be remotely exploitable. The predictable staging path is the flaw; the upgrade window is the opportunity. Patch to 7.1.4 to remove the predictability, block the staging directory to remove the exposure, and the race has nowhere left to run.