WordPress GHSA-4w3m-c66w-69mg lets attackers hijack sites mid-update; here's how to patch and check it on your clients' WordPress sites.
For a few seconds while WordPress updates itself, a fresh copy of its own installer sits in a public folder, and anyone who reaches it first can run code on the server. Attackers know it: according to The Hacker News, Wordfence blocked 62,969 attack attempts against the WordPress core update race in 24 hours, with two sources polling the same small groups of sites for about 14.5 hours, waiting for that window.
The twist: the dangerous moment is the update itself. Patching is still the cure, but on a vulnerable site the window opens every time an update unpacks.
/wp-content/upgrade/ is web-reachable; the advisory lists branch fixes such as 7.0.8 and 6.9.11./wp-content/upgrade/, then update every client site, and search access logs for PHP requests under that folder.The WordPress upgrade-race RCE is a flaw in how WordPress core installs a full-package update. WordPress's GitHub advisory says affected versions extract the new files "to a predictable directory inside the web-served upgrade folder", and an unauthenticated attacker who wins the race against that extraction could get remote code execution. The researcher credited is Umut Bayram.
Think of a locksmith who swaps your front-door lock by leaving the new one, with its keys, on the porch for a few seconds. The staged copy includes the WordPress installer, a page built to set up a site for whoever asks. An attacker who reaches it before WordPress cleans up can reach PHP code execution, according to The Hacker News' summary of Wordfence's analysis.
The severity depends on who you ask. The GitHub advisory labels it Low; Wordfence scores it CVSS 8.1, per The Hacker News. The gap makes sense: the window lasted only seconds in Wordfence's lab tests, but a site that updates on a schedule tells patient attackers roughly when to knock.
Attackers are actively trying. According to The Hacker News, Wordfence blocked 62,969 attempts in 24 hours, saw two of the largest sources poll small groups of sites for roughly 14.5 hours, and saw others cycle through staging-folder and version-name guesses, with setup-config.php among the paths hit. Blocked attempts are not break-ins: we found no public report of a confirmed compromise, and none of the sources we read named victims or attacker IP addresses.
A client site is affected if it runs WordPress core 4.7 through 7.1.3 without its branch's fix, and the web server serves files from /wp-content/upgrade/. The advisory lists the fixed releases: 7.1.4, 7.0.8, 6.9.11, 6.8.12, 6.7.11, 6.6.11, 6.5.14, and older branches down to 4.7.39. WordPress's release post says backports "will ship as they become ready", so confirm a branch's release exists before relying on it. WordPress 4.6 and older get nothing.
Run these as root on the client's web server. They search the whole disk, so they catch every WordPress install, not just the main site. To cover a fleet, save the commands of steps 1–5 as checks.sh, list servers in hosts.txt, and run:
while read h; do echo "== $h"; ssh "$h" 'sudo bash -s' < checks.sh; done < hosts.txt
D=/root/wp-evidence-$(date +%F); sudo mkdir -p "$D"
sudo cp -a /var/log/apache2 /var/log/nginx /var/www "$D"/
sudo find "$D" -type f -exec sha256sum {} + | sudo tee "$D.sha256"
sudo find / -path /proc -prune -o -path '*/wp-includes/version.php' -exec grep -H '^\$wp_version' {} +
for c in $(sudo docker ps -q); do sudo docker exec "$c" find / -path /proc -prune -o -path '*/wp-includes/version.php' -exec grep -H '^\$wp_version' {} +; done
.gz logs. Pass: no lines. Any line with a 200 response deserves a closer look. If a control panel keeps logs elsewhere, add that path.sudo zgrep -hE 'wp-content/upgrade/[^ ]*\.php' /var/log/apache2/*access* /var/log/nginx/*access*
index.php files.sudo find / -path /proc -prune -o -path '*/wp-content/upgrade/*' -name '*.php' ! -name index.php -print
user list and core verify-checksums. Pass: only admins the client recognises, none registered on or after October 28, 2026 without a reason, and "Success: WordPress installation verifies against checksums." under every path.sudo find / -path /proc -prune -o -path '*/wp-includes/version.php' -print | while read f; do p=$(dirname "$(dirname "$f")"); u=$(stat -c %U "$f"); echo "== $p"; sudo -u "$u" wp --skip-plugins --skip-themes --path="$p" user list --role=administrator --fields=user_login,user_registered; sudo -u "$u" wp --skip-plugins --skip-themes --path="$p" core verify-checksums; done
The loop runs WP-CLI as the user that owns the files, never as root, and with --skip-plugins --skip-themes, so a planted plugin on a hit site doesn't run during the check. If root owns an install, WP-CLI refuses to run and prints an error; for that install, review admins in the dashboard under Users > All Users > Administrator, and report it as not checksum-verified.
Close the folder first, then patch, so the window can't open while the fix itself installs.
/wp-content/upgrade/. On nginx, add this inside the site's server block (nginx's deny directive is valid in a location; ^~ stops PHP regex locations from matching first). On Apache, add the second line to the vhost or .htaccess (RedirectMatch with a 403 needs AllowOverride FileInfo in .htaccess). For a site installed in a subfolder, put that folder in front of the path.location ^~ /wp-content/upgrade/ { deny all; }
RedirectMatch 403 "^/wp-content/upgrade/"
sites.txt, one per line, and run this. Pass: every domain prints 403.while read s; do printf '%s ' "$s"; curl -s -o /dev/null -w '%{http_code}\n' "https://$s/wp-content/upgrade/"; done < sites.txt
sudo find / -path /proc -prune -o -path '*/wp-includes/version.php' -print | while read f; do sudo -u "$(stat -c %U "$f")" wp --skip-plugins --skip-themes --path="$(dirname "$(dirname "$f")")" core update; done
For an MSP, the hard part isn't the patch; it's knowing which clients' sites run WordPress, which version, and whether the upgrade folder answers from the internet, the same things attackers checked at scale this week. KinoSec's autonomous web app pentest does that reconnaissance with your client's permission: it maps the external surface, fingerprints what's running, finds vulnerabilities and misconfigurations like a web-reachable staging folder, and writes up the findings with remediation in a report you can hand your client. Run it on demand after a release like 7.1.4, or continuously, so the next WordPress fire drill starts with a list instead of a guess.
GHSA-4w3m-c66w-69mg is WordPress's GitHub advisory for a race condition during core updates that could lead to remote code execution. It affects WordPress 4.7 through 7.1.3 and is fixed in 7.1.4, released October 28, 2026, with backports such as 7.0.8 and 6.9.11. The advisory lists no CVE id.
Attackers are trying it: according to The Hacker News, Wordfence blocked 62,969 attempts in 24 hours. We found no public report of a confirmed break-in yet. Patch anyway, because attackers are polling sites for hours to catch the update window.
First, preserve evidence by copying logs and the web root and hashing them. Then search the access logs with zgrep -hE 'wp-content/upgrade/[^ ]*\.php'; any line needs a closer look. Finally, list leftover PHP files under wp-content/upgrade and run wp core verify-checksums and wp user list --role=administrator in every install.
Yes, once a site reaches 7.1.4 or its branch's fixed release, WordPress's advisory lists it as patched. The window opens while an update unpacks, which is why attackers polled sites for hours. Blocking web access to /wp-content/upgrade/ before updating keeps it shut and protects any install you haven't reached yet.