CVE-2026-119977: The WordPress Update Button Became the Attack Surface
Nov 7, 2026 · @Thomas J. Raef
For a few seconds during every WordPress core update before 7.1.4, a complete, unconfigured copy of WordPress sat at a guessable URL on your site. Attackers are now hammering that window, and on November 3, 2026, CISA added CVE-2026-119977 (CVSS 8.1) to its Known Exploited Vulnerabilities catalog.
Credit first. The flaw was found and responsibly reported by Umut Bayram of Picus Security, and WordPress patched it in 7.1.4 on October 28, with fixes backported to every branch down to 4.7. The reason the rest of us know how fast it went from patch to attack is the Wordfence team. Wordfence assigned the CVE, published the technical analysis, shipped a firewall rule the night the patch dropped, and saw the first matching attack nine minutes later. Their telemetry is what turned a “high complexity, probably impractical” bug into a confirmed, actively exploited one. Hats off to both.
Below I’ll explain how the bug works, what attackers are doing, what we see across the 4 million+ WordPress sites we monitor, and why this one made me rethink something I’ve been saying for 18 years about hiding your WordPress version.
How the bug works
It is a time-of-check time-of-use (TOCTOU) race condition, CWE-367, in the core updater itself. No plugin or theme is involved, and no login is needed. Affected: WordPress 4.7.0 through 7.1.3.
A full-package core update runs in five steps:
- Download the release ZIP.
- Extract it into a working directory under
wp-content/upgrade/. - Check the known package files (unexpected extra files are not rejected).
- Copy the new files over the live site.
- Delete the working directory.
The problem is step 2. Before 7.1.4, the working directory was named after the package file, with no randomness:
$working_dir = $upgrade_folder . basename( basename( $package, '.tmp' ), '.zip' );
So a site updating to 7.1.4 unpacked into something like wp-content/upgrade/wordpress-7.1.4-no-content/wordpress/. That folder is a complete WordPress install, including wp-admin/setup-config.php, the installer that runs when it finds no configuration. On most servers it is reachable over the web, and the cleanup step also removed the index.php that keeps the folder from being listed.
An attacker who hits that installer during the window can point it at a database they control and get PHP execution inside your document root. Bayram’s write-up goes further: because the updater copied staged files over the live site, a wp-config.php planted in the staging tree could replace your real one.
The window is short. Wordfence found the staging folder normally lasts only seconds in lab testing, so a single request almost never lands. Repeated, automated polling changes the odds.
WordPress 7.1.4 fixes it three ways: the working directory now gets 16 random characters added to its name, the upgrade folder’s index.php is kept and recreated if missing, and wp-config.php is never copied out of the working directory.
One thing worth stressing: a PHP-level firewall plugin cannot stop this. The staged copy loads its own files, so your site’s security plugin never runs for that request. The block has to happen at the web server, WAF or CDN layer.
What attackers are doing
Attackers started probing within minutes of the patch and have not let up. Wordfence logged more than 18,500 requests to staged setup-config.php paths in the first 21 hours, and The Hacker News reports 12,632 attacks blocked in a single 24-hour period.
The behavior matters more than the totals. Wordfence saw two of the largest sources poll small groups of sites over and over for roughly 14.5 hours, which only makes sense if you are trying to catch an update in progress. Other sources cycled through many staging-directory and version-name variations. In other words, they understood the race and were guessing which package name a given site would unpack.
| Date (2026) | Event |
|---|---|
| Nov 4 | Umut Bayram publishes his full write-up |
| Nov 3 | CISA adds CVE-2026-119977 to KEV; federal agencies given until Nov 6 |
| Oct 31 | CVE published, assigned by Wordfence as CNA |
| Oct 30 | Previdian honeypot records exploitation attempts |
| Oct 29 | WordPress publishes its advisory; Wordfence publishes its analysis |
| Oct 28 | WordPress 7.1.4 released; Wordfence firewall rule live, first hit 9 minutes later |
Wordfence has not reported a confirmed successful compromise. That is not the same as none happening: a successful attack lands during an update, the evidence sits in a folder the updater deletes moments later, and most site owners never look.
What we see in our own data
Across the sites we monitor, requests for the WordPress installer inside the upgrade folder went from zero to 26,559 in ten days.
We pulled every request for a PHP file under wp-content/upgrade/ from October 28 through the morning of November 7, and compared it with the 30 days before the patch. Nobody outside your server ever needs those files, so every hit is a probe.
| Measure | 30 days before patch | Oct 28 to Nov 7 |
|---|---|---|
Requests for PHP files under wp-content/upgrade/ | 266,266 (about 2,200 a day) | 130,482 (about 13,000 a day) |
Requests for setup-config.php | 0 | 26,559 |
| Source IPs | 2,280 | 19,888 |
The upgrade folder itself is not a new target. Attackers have long used it to stash web shells, and probes for files like shell.php make up most of the background noise. What changed on October 28 is the installer: 30 days of zero, then thousands of requests across 12,285 sites.
The attacks came in two waves. One OVH address, 51.89.103.78, opened the first at 5:32 pm ET on October 29 and sent 2,684 requests to 712 sites over the next 23 hours. Going by Rescana’s timeline, that was roughly two hours after WordPress published its advisory and before Wordfence’s analysis went live. Installer probes then nearly stopped from October 31 to November 2. They came back the day CISA added the flaw to its KEV catalog and have risen every day since.
The second wave is broader, too: 637 different addresses sent installer probes on November 6, against at most 9 on any day of the first wave.
Attackers guess the folder name, and some guesses depend on your version. These were the most-tried staging folders:
| Staging folder guessed | Requests | Source IPs |
|---|---|---|
| wordpress-7.1.4 | 1,348 | 15 |
| wordpress | 1,190 | 11 |
| wordpress-7.1.3 | 1,066 | 9 |
| wordpress-7.0.8 | 244 | 5 |
| wordpress-6.9.11 | 244 | 5 |
| wordpress-7.0.7 | 167 | 4 |
| wordpress-latest | 162 | 1 |
| core | 160 | 2 |
| wordpress-7.1-no-content | 157 | 2 |
| wordpress-7.0.8-no-content | 121 | 2 |
7.0.8 and 6.9.11 are the fixed releases for the 7.0 and 6.9 branches. A guess like wordpress-6.9.11 only works on a site running 6.9, so we looked at how each scanner picked its names. We found three approaches:
- The same three guesses everywhere. 51.89.103.78 sent
wordpress,wordpress-7.1.4andwordpress-7.1.3to every one of its 712 sites. It never checked what a site was running. - Every version name there is. Other scanners walk through long lists: one address tried 188 different folder names against a single site, another tried 51 on each of three sites. This is what you do when you don’t know the version.
- Different guesses for different sites. 45.148.10.122, active since November 4, sent different sets of names to different sites across 167 sites. Most got 7.1-branch names, a few got 7.0-branch names such as
wordpress-7.0.8-new-bundled, and one got 6.9-branch names such aswordpress-6.9.11-no-content. It also knows WordPress’s real package types (no-content,new-bundled). [FILL: confirm the sites it sent 7.0 and 6.9 names to really run those branches]
One scanner camped on a single site. 103.59.160.171 sent 1,972 requests to one site over about 19 hours on October 28 and 29, cycling through six folder names including wordpress-7.0.8 and wordpress-6.9.11. That is what waiting for one particular site to start updating looks like.
The tooling is sloppy. Several scanners, including 51.89.103.78 and 62.60.130.26, followed a site’s redirect to its login page and then stuck the staging path on the end of the login URL. Those requests hit the login page, not the installer. They also show the playbook: three guesses (wordpress/, wordpress-7.1.4/, wordpress-7.1.3/) fired within about two seconds, and a heavy focus on staging.* subdomains, which tend to lag behind on updates. Most of the traffic identified as Go-http-client/2.0 (12,712 requests from 599 IPs), much of it from Oracle Cloud and Microsoft address space.
No sign of a successful hit. Of the 130,482 requests, 115,923 got a 404, 11,303 were blocked with a 403, and 2,391 were dropped outright. Most 200 responses on an installer path was the login-page mix-up described above, and no request for a guessed staging folder came back with a 200.
Was I wrong about hiding the WordPress version?
For years I have said there is no logic in hiding your WordPress version. Attackers don’t check versions, they just fire the exploit at everything. This bug is the first time I’ve had to qualify that.
Here is the honest breakdown.
Your version decides which folder name works. The staging folder is named after the package being installed. A site on 7.1 unpacks a 7.1.4 package, but a site on 6.9 unpacks 6.9.11, and the package type (no-content, new-bundled) changes the name too. So an attacker who knows your branch can go straight to the right name.
But your version tells an attacker when to show up. An update-window bug is different from a normal exploit because it only works during the update. That makes two questions valuable:
- Is this site still on a vulnerable version? A site already on 7.1.4 is a waste of requests. A site still showing 7.1.3 days after release is about to update, or has auto-updates off and will update manually at some point.
- Has it updated yet? Watching the version string flip tells an attacker the window opened and closed, so they can move on. The current version also hints at which package a site will pull (a partial update versus a full one), and only the full package carries the installer.
The pattern Wordfence describes, a few sources polling small groups of sites for 14.5 hours, fits an attacker who has already picked sites worth watching. I can’t prove that’s how they picked them, but a public version string is the cheapest way to build that list.
So, does hiding it help? A little, against this class of bug, and that’s more than I used to give it credit for. It still won’t save you. The version leaks in plenty of other places: ?ver= on script and style URLs, readme.html, feed generator tags, and fingerprints of core files. And attackers can simply poll everyone and eat the cost.
Our own logs put a number on it. In a race that lasts a few seconds, the scanner that had to try 188 folder names on one site is far less likely to land on the right one in time than a scanner that knows to try one. A hidden version doesn’t stop the attack, but it can turn a one-request guess into a 188-request guess.
My updated position: hiding your version is still weak hardening, not a defense. But “there’s no logic in it” was too strong. As update-window bugs show up, your version stops being just “what you run” and becomes “when you’ll be vulnerable,” and that’s information worth not handing out for free. The real fixes are below, and they work whether your version is visible or not.
What to do now
Update to 7.1.4, or your branch’s fix (7.0.8, 6.9.11, 6.8.12 and so on back to 4.7.39), and block web access to wp-content/upgrade/ first. The update to the patched version still runs through the old, vulnerable updater one last time, so close the door before you walk through it.
- Block the upgrade folder at the web server. Nothing outside your server ever needs to load it.
nginx:location ^~ /wp-content/upgrade/ { return 403; }
Apache (.htaccessin the site root, needs mod_alias):RedirectMatch 403 ^/wp-content/upgrade/ - Update core through the dashboard or
wp core update, then confirm withwp core version. Don’t assume auto-updates finished. - Check your logs before you clean up. Look for any request to a PHP file under
wp-content/upgrade/, especiallysetup-config.php. A 200 response during an update window should be treated as a compromise. - Look for leftovers. Anything sitting in
wp-content/upgrade/, admin users nobody created, plugins nobody installed, and awp-config.phpwith a timestamp that matches an update. - Find the forgotten sites. Old staging and dev copies, and anything on 4.6 or older, which gets no fix at all.
Keep the server rule in place after you patch. Every future core update opens a window like this, and the next updater bug won’t come with advance notice.
If you’re a We Watch Your Website customer, we’ve been watching your files. Our logs and systems go into overdrive every time there’s a WP Core update. We did notice new processes running on a few sites. The hackers had hit the window precisely at the right time, uploaded a file, ran it and it created a process that was running in the background. We remediated those immediately.
Does turning off auto-updates protect you?
No. The window opens during any core update on a vulnerable version, however it starts: an automatic background update, clicking Update Now, wp core update, or your host’s update tool. Minor and security auto-updates have been on by default since WordPress 3.7, so most sites opened this window on their own, with nobody touching anything. That’s exactly why attackers poll and spray: they can’t know when a given site’s background update will run.
Turning auto-updates off doesn’t close the window. It moves it to whenever you finally update. Until then, your site stays exposed to the other 21 flaws fixed in 7.1.4. When you do update, that update still runs through the old, vulnerable updater one last time. These sites may be attacked weeks from now, long after everyone else has patched.
The fix is the same either way: block web access to /wp-content/upgrade/ at the web server, then update. Leave auto-updates on.
Sources
- CISA confirms hackers exploiting WordPress core flaw, The Hacker News
- CVE-2026-119977 record, cve.org
- WordPress 7.1.4 release notes, WordPress.org
- WordPress 7.1.4 security release analysis, Wordfence
- CVE-2026-119977: When Updating WordPress Becomes the Vulnerability, Umut Bayram, Picus Security
- Attackers actively probing for upgrade-window RCE in WordPress core, Wordfence post via Malware News
- WordPress 7.1.4 fixes 22 flaws, one in the core update process, summarizing Patchstack’s analysis
