Vulnerability
Inside CVE-2026-119977: The 18-Year-Old WordPress Core Flaw Enabling Pre-Auth Remote Code Execution
An exhaustive vulnerability research analysis of CVE-2026-119977, an 18-year-old Time-of-Check to Time-of-Use (TOCTOU) race condition in WordPress Core added to CISA's Known Exploited Vulnerabilities catalog. We deconstruct the upgrader package extraction mechanics, model the exploitation race window, analyze honeypot telemetry across 240,000+ attacks, and provide enterprise hardening rules.
8 min read
Executive Summary: An 18-Year Flaw Weaponized at Scale
On November 3, 2026, the Cybersecurity and Infrastructure Security Agency (CISA) officially added CVE-2026-119977 to its Known Exploited Vulnerabilities (KEV) Catalog, setting an urgent remediation deadline for federal civilian executive branch agencies. Rated as a high-severity flaw with a Common Vulnerability Scoring System (CVSS v3.1) base score of 8.1, the vulnerability enables unauthenticated remote attackers to execute arbitrary code on web servers running WordPress Core. Over the past 72 hours, threat intelligence sensors and global perimeter honeypots registered more than 240,000 active exploitation attempts targeting internet-exposed deployments worldwide.
While the overwhelming majority of CMS vulnerabilities reside in poorly maintained third-party plugins or abandoned commercial themes, CVE-2026-119977 is rooted directly inside WordPress Core. Discovered by security researcher Umut Bayram of Picus Security, the underlying vulnerability is a critical Time-of-Check to Time-of-Use (TOCTOU) race condition within the core upgrade extraction subsystem (WP_Upgrader).
+-----------------------------------------------------------------------------------------+
| CVE-2026-119977 THREAT TELEMETRY |
+-----------------------------------------------------------------------------------------+
| IDENTIFIER: CVE-2026-119977 | SEVERITY: CVSS 8.1 (High) / CISA KEV Listed |
| AFFECTED: WordPress Core 4.7 - 7.1.3 | PATCH VERSION: WordPress 7.1.4 / 4.7.39 |
| VULNERABILITY CLASS: Pre-Auth RCE | ROOT CAUSE: TOCTOU Unpack Race Condition |
+-----------------------------------------------------------------------------------------+
|
v
+-----------------------------------------------------------------------------------------+
| ATTACK SURFACE & INGRESS VECTOR |
| (Unauthenticated Remote HTTP Traffic Targeting Upgrade Extraction Window) |
+-----------------------------------------------------------------------------------------+
|
v
+-----------------------------------------------------------------------------------------+
| WORDPRESS CORE UPGRADE SUBSYSTEM |
| 1. Admin or Auto-Cron triggers update via wp-admin/includes/class-wp-upgrader.php |
| 2. Archive downloaded from wordpress.org and unpacked into wp-content/upgrade/ |
| 3. [EXPLOITATION WINDOW]: Temporary files land in web-accessible document root! |
| 4. Attacker sprays requests to execute unverified PHP payloads prior to atomic rename |
+-----------------------------------------------------------------------------------------+
|
v
+-----------------------------------------------------------------------------------------+
| POST-EXPLOITATION IMPACT |
| (Web Shell Installation, Database Exfiltration, Persistent C2 Beaconing) |
+-----------------------------------------------------------------------------------------+
Architecturally, the flaw traces back to WordPress 2.7 released in 2008. For eighteen years, the core updater unpacked upgrade packages into predictable, web-accessible temporary directories before verifying permissions and moving files into place. In automated update environments, this creates an exploitation window during which an attacker can execute arbitrary PHP code without authentication.
Technical Anatomy: Root Cause and TOCTOU Race Condition
To understand how CVE-2026-119977 facilitates remote code execution, one must examine how WordPress updates its own files.
When WordPress installs a core update (whether triggered manually by an administrator or automatically via background cron), it invokes WP_Upgrader::run() defined in wp-admin/includes/class-wp-upgrader.php:
CHRONOLOGICAL LIFECYCLE OF CORE UPDATE EXECUTION
+-----------------------------------------------------------------------------------------+
| 1. Download: Fetch zip package from api.wordpress.org to local system temp |
+-----------------------------------------------------------------------------------------+
|
v
+-----------------------------------------------------------------------------------------+
| 2. Unpack: Extract zip archive into $wp_filesystem->wp_content_dir() . 'upgrade/' |
| Path: /wp-content/upgrade/core-temp-xxxxxxxx/wordpress/ |
+-----------------------------------------------------------------------------------------+
|
+-------------------------+-------------------------+
| |
v (Normal Execution Path) v (Attacker Exploitation)
+---------------------------------------+ +-------------------------------------+
| 3. Verification & Atomic Move | | [RACE WINDOW: 100ms - 2,500ms] |
| - Check filesystem permissions | | Attacker floods HTTP GET requests |
| - Move files to root (/var/www/html) | | to predictable temp file URL |
| - Delete temporary upgrade folder | | Web server executes raw PHP script! |
+---------------------------------------+ +-------------------------------------+
The Flawed Extraction Routine
In vulnerable versions (4.7 through 7.1.3), the upgrader extracts files into a subdirectory under wp-content/upgrade/. The destination folder name was generated using pseudo-random seeds that could be predicted or bruteforced, or followed predictable directory patterns:
// Vulnerable logic pattern in class-wp-upgrader.php
$working_dir = $this->fs_connect( array( WP_CONTENT_DIR . '/upgrade' ) );
$unique_dir = WP_CONTENT_DIR . '/upgrade/' . basename( $package, '.zip' );
// Unpack archive directly into the web-accessible document root
$result = unzip_file( $package, $unique_dir );
/*
* TOCTOU RACE CONDITION WINDOW:
* At this exact millisecond, all extracted files reside inside
* http://example.com/wp-content/upgrade/wordpress/
*
* Neither .htaccess nor index.php protection existed within subdirectories.
* File permissions were checked AFTER the extraction completed!
*/
$this->install_package( array(
'source' => $unique_dir,
'destination' => ABSPATH,
'clear_destination' => false,
'abort_if_destination_exists' => false,
) );
Exploit Mechanics: Spraying the Race Window
Because web servers (Nginx, Apache with PHP-FPM) are configured to execute any .php file requested under the document root, any PHP file created during the extraction becomes executable if requested before the upgrader deletes or moves it.
Attackers exploit this via a two-stage mechanism:
- Triggering or Predicting Upgrades: Attackers monitor target sites for minor version releases or trigger update check routines. When an unattended background update starts, the extraction begins. On shared hosting platforms, local co-tenant attackers can leverage Linux kernel
inotifyorfanotifyhooks to receive instantaneous notifications the moment a file creation event registers in/wp-content/upgrade/. - Concurrent Request Spraying: The attacker launches a multi-threaded flood of HTTP requests probing candidate temporary paths. If an attacker manages to write or manipulate a file in that directory—or if the temporary package contains an unauthenticated hook—the web server executes the script in the context of the
www-datauser, yielding full remote code execution.
Below is a Python demonstration script modeling how security analysts detect the TOCTOU race condition window:
# Exploit telemetry validation script
import requests
import threading
import time
TARGET_URL = "https://target-site.local"
PROBE_PATH = "/wp-content/upgrade/core-temp/wordpress/wp-admin/setup-config.php"
stop_event = threading.Event()
def race_worker(worker_id):
while not stop_event.is_set():
try:
resp = requests.get(TARGET_URL + PROBE_PATH, timeout=0.8)
if resp.status_code == 200:
print(f"[!] Race condition hit! Worker {worker_id} accessed transient file.")
stop_event.set()
return
except requests.RequestException:
pass
threads = [threading.Thread(target=race_worker, args=(i,)) for i in range(32)]
for t in threads:
t.start()
Threat Telemetry & Production Impact
Data gathered across honeypots and enterprise hosting providers underscores the scale of active exploitation:
| Metric / Observed Factor | Recorded Value / Characteristic | Impact on Target Fleet |
|---|---|---|
| Exploitation Velocity | >240,000 attempts in 72 hours | Mass scanning across shared hosting clusters |
| CVSS v3.1 Score | 8.1 (High): CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H |
Pre-auth exploitation without user interaction |
| Average Race Window | 120ms (NVMe) to 2,400ms (Slow HDD) | Longer windows on resource-constrained servers |
| Affected Core Versions | WordPress 4.7 through 7.1.3 | Estimated >40% of public WordPress installations |
| Observed Payloads | Obfuscated PHP Web Shells, XMRig miners | Full compromise of hosting account and database |
Race Window Duration vs. System Storage Architecture:
Fast NVMe Storage (High IOPS): [== ] ~120ms Window (Lower Exploit Probability)
Cloud Block Storage (EBS / SAN): [====== ] ~650ms Window (Moderate Exploit Probability)
Shared Hosting (Mechanical HDD): [========] ~2,400ms Window (HIGH Exploit Probability)
The probability of successful exploitation scales with storage latency. On budget virtual private servers or shared hosting systems where disk I/O is throttled, the unpack-and-move sequence takes multiple seconds, widening the race window significantly. Furthermore, botnets utilize distributed IP proxies to synchronize burst requests, maximizing their chance of hitting the exact millisecond when intermediate PHP files reside on disk.
Remediation & Hardening Playbook
Mitigating CVE-2026-119977 requires immediate patching accompanied by web server and filesystem hardening.
1. Core Upgrade Directives
Upgrade immediately to the patched releases. WordPress released 7.1.4 along with security backports extending back to branch 4.7:
# Update WordPress core using WP-CLI
wp core update --version=7.1.4
# Verify core integrity and checksums
wp core verify-checksums
2. Web Server Direct Execution Restrictions
The primary reason this flaw enables RCE is that web servers allow direct PHP execution within wp-content/. Web servers should be configured to reject execution of any scripts inside upload and upgrade directories.
Nginx Hardening Directive
Add the following block to your server configuration in /etc/nginx/sites-available/wordpress:
# Block PHP execution in upload, upgrade, and cache directories
location ~* ^/wp-content/(uploads|upgrade|cache)/.*\.php$ {
deny all;
access_log off;
log_not_found off;
return 403;
}
Apache (.htaccess) Protection
Create or update /wp-content/upgrade/.htaccess:
# Deny direct execution of scripts in upgrade directory
<Files *.php>
Order Deny,Allow
Deny from all
</Files>
3. Web Application Firewall (WAF) & ModSecurity Signatures
For enterprise infrastructure fronted by ModSecurity or Cloudflare WAF, deploy immediate virtual patching rules targeting upgrade path probing:
# ModSecurity Rule to block unauthenticated requests to the upgrade directory
SecRule REQUEST_URI "@rx ^/wp-content/upgrade/.*\.php$" \
"id:1000045,\
phase:1,\
deny,\
status:403,\
log,\
msg:'Blocked potential CVE-2026-119977 WordPress Core RCE exploit attempt'"
4. Securing wp-config.php and Filesystem Permissions
Force WordPress to utilize secure direct filesystem writes and relocate the temporary directory outside the public web document root:
// Add to wp-config.php outside web root
define( 'FS_METHOD', 'direct' );
// Move temporary upgrade path outside the public HTML directory
define( 'WP_TEMP_DIR', '/var/www/secure_tmp/' );
Ensure the /var/www/secure_tmp/ folder is owned by the web server user (www-data:www-data) with strict 0700 permissions and is physically located outside /var/www/html/.
Semantic FAQ Section
What is the root cause of CVE-2026-119977?
The root cause is a Time-of-Check to Time-of-Use (TOCTOU) race condition in WordPress Core's WP_Upgrader class. When updates are installed, packages are unpacked into a temporary, web-accessible folder inside wp-content/upgrade/ before permission validation occurs, enabling an unauthenticated attacker to execute transient PHP files before they are relocated or deleted.
Why did this vulnerability remain undiscovered for 18 years?
The vulnerability dates back to the file extraction architecture introduced in WordPress 2.7 in 2008. Because the flaw only surfaces during the brief execution window of an active core update, standard static application security testing (SAST) tools and point-in-time penetration tests failed to catch the transient race window.
Does CVE-2026-119977 require an administrator account to exploit?
No. Exploitation is completely unauthenticated. Any remote network attacker who can reach the site during an active upgrade window and guess or probe the temporary extraction directory can trigger execution without credentials or administrative privileges.
How does moving WP_TEMP_DIR prevent exploitation?
By defining WP_TEMP_DIR in wp-config.php to point to a filesystem directory located outside the web server's document root (such as /var/www/secure_tmp/), temporary upgrade archives are unpacked in a path that the web server cannot serve over HTTP, eliminating the execution vector even if the race condition occurs.
What versions of WordPress are patched against this flaw?
The flaw is patched in WordPress version 7.1.4. In addition, the WordPress security team backported fixes to all supported legacy release branches, including versions 4.7.39, 5.0.33, 6.0.21, and 7.0.12.