WordPress core itself got a pre-auth RCE. Installing the update does not tell you whether you were already breached
wp2shell chains CVE-2026-63030, a REST API batch-route confusion bug, with CVE-2026-60137, a SQL injection in WP_Query, into unauthenticated remote code execution on a default WordPress install with no plugins involved. WordPress 7.0.2 shipped July 17, 2026 and WordPress.org force-pushed it. CISA added both CVEs to the Known Exploited Vulnerabilities catalog on July 21 and gave federal agencies three days on one of them. Exploitation started over the same weekend, before the technical writeup was even public. Six weeks on, WordPress.org's own statistics API still puts 27.9 percent of installs on the two branches that carried the full chain. Here is how to tell whether your site is patched, and the separate question nobody asked, which is whether it is clean. Version figures refreshed August 27, 2026.
Almost every WordPress security story a small business owner has ever been told follows the same script: a plugin nobody has updated since 2021 turns out to have a hole in it, and the fix is to update the plugin or delete it. That script has been broadly accurate for a decade, and it is the reason “keep your plugins patched” is the entire security advice most site owners have ever received.
July 2026 broke the script. The vulnerability was in WordPress core. It worked on a default install with no plugins, no theme, and no logged-in user.
What wp2shell actually is
Two bugs, and the interesting part is the join.
CVE-2026-63030 is a route confusion flaw in the REST API batch endpoint at /wp-json/batch/v1. WordPress validated the queued sub-requests in one loop and executed them in a second loop, and the two loops could be knocked out of step. Once desynchronised, every subsequent sub-request dispatches under the wrong handler, which means a request gets executed with validation that belonged to a different request. It was reported by Adam Kues of Assetnote, part of Searchlight Cyber.
CVE-2026-60137 is a SQL injection: WordPress did not properly sanitise the author__not_in parameter of WP_Query. On its own this one is close to harmless, because core never passes untrusted input to that parameter. It only becomes exploitable if a plugin or theme hands user input to it. Reported by TF1T, dtro and haongo.
Chained, the batch desynchronisation is what supplies the untrusted input that the SQL injection needs, without any plugin being involved at all. The result is pre-authentication UNION-based SQL injection, which the public exploits turn into an administrator account and then a plugin upload, which is remote code execution. Searchlight Cyber demonstrated it against a stock WordPress installation. Somebody named the chain wp2shell and the name stuck.
This is worth pausing on, because it is the recurring lesson in application security and it almost never lands until it happens to you. Two findings that a triage process would reasonably have rated “medium” and “not exploitable in core” combined into full site takeover. Neither bug was a big deal. The pair was.
The scoring reflects that confusion. WPScan rated CVE-2026-63030 at 9.8 critical and CVE-2026-60137 at 5.9 medium. CISA’s own analysts scored the same two at 7.5 high and 9.1 critical respectively. The two organisations disagree about which half of the chain is the dangerous one, which tells you something useful: a CVSS number describes a bug in isolation, and the thing that compromised sites was not a bug in isolation.
The timeline, and how little slack there was in it
- Friday, July 17, 2026. WordPress 7.0.2 ships, alongside backports as 6.9.5 (both bugs) and 6.8.6 (the SQL injection only). Versions before 6.8 are unaffected. The release post says plainly: “It is recommended that you update your sites immediately.” The WordPress.org team enabled forced updates through the auto-update system for sites running affected versions, which is a lever they pull very rarely.
- The same weekend. Exploitation begins. Hexastrike reported detections in its honeypots and said that by Sunday it had already assisted with incident response on several real attacks. watchTowr and Patchstack independently confirmed in-the-wild attempts. Wordfence saw endpoint probing and SQL injection attempts the same evening the patch landed.
- Tuesday, July 21. CISA adds both CVEs to the Known Exploited Vulnerabilities catalog. Under the new BOD 26-04 risk-based patching rules, CVE-2026-63030 got a three-day federal remediation deadline of July 24. CVE-2026-60137 got until August 4.
- Wednesday, July 22. Searchlight Cyber publishes the full technical writeup. Working proof-of-concept exploits appear on GitHub.
Note the ordering. Exploitation preceded the public technical writeup. The gap between “a patch exists” and “attackers know what it fixes” is now measured in hours, because diffing a security release is a routine, largely automated exercise. Waiting for a maintenance window is no longer a neutral choice.
The bit that most coverage skipped
Here is what a compromised site looked like, drawn from the SANS Internet Storm Center diary and Wiz’s incident telemetry:
- A PHP webshell dropped into
wp-content/cache/, with a hardcoded authentication key and a deliberate touch: it returns a 404 even though the file exists, so a casual check for it looks like a clean miss. - A backdoor plugin installed through
/wp-admin/update.php?action=upload-plugin, using the administrator session the SQL injection produced. Wiz found three webshell variants, from a one-line dropper up to a 150KB toolkit with file management, database access, port scanning and privilege escalation built in. - New administrator accounts in
wp_users. - Reads of
/wp-json/wp/v2/users?context=editto harvest account details, and local file inclusion attempts aimed atwp-config.phpand the authentication salts.
Every one of those survives an update to 7.0.2. The patch closes the door. It does not remove anyone already inside. A rogue admin account, a webshell in the cache directory, and a stolen set of auth keys all keep working perfectly on a fully patched, fully current WordPress site. Malwarebytes documented what the sites got used for afterwards: credential phishing, malware delivery and fraudulent redirects served to ordinary visitors.
If your site was running an affected version and was reachable from the internet at any point between July 17 and whenever it actually updated, patching is step one of two, and step two is the one nobody did.
Where things stand today
We pulled these numbers from the WordPress.org statistics API on August 27, 2026, refreshing the figures this post originally carried from August 22. It reports the share of installs on each release branch:
| Branch | Share of installs | August 22 |
|---|---|---|
| 7.1 | 47.7% | 43.4% |
| 7.0 | 19.3% | 23.1% |
| 6.9 | 8.6% | 8.8% |
| 6.8 | 6.3% | 6.4% |
| 6.7 and older | 18.2% | 18.3% |
Five days of movement, and it is worth reading carefully because the shape of it is the point. The 7.1 branch gained 4.3 points, almost exactly what 7.0 lost. Sites that are on auto-update kept doing what auto-update does. Meanwhile 6.9 moved by 0.2 points, 6.8 by 0.1, and 6.7 and older by 0.1. The population that had not patched a month after a force-pushed emergency release is the same population that will not patch this month either. That is not a backlog clearing slowly. It is a fixed set of sites nobody is maintaining.
Two honest caveats before anyone quotes this. The API reports branches, not point releases, so the 19.3% on 7.0 includes both the patched 7.0.2 and the vulnerable 7.0.1, and there is no way to split them from this data. And the figures only cover installs that phone home to WordPress.org, which systematically undercounts abandoned and firewalled sites, the exact population least likely to have updated.
What the table does show is the shape of the problem. 27.9% of installs are on the 6.9 or 7.0 branches, the two that contained the full wp2shell chain, and another 6.3% are on 6.8, which was exposed to the SQL injection half. An unknowable but non-zero slice of those has never taken the patch.
And 18.2% are on 6.7 or older, which is the genuinely alarming row. Those sites were untouched by wp2shell, because the batch endpoint bug did not exist before 6.8, and that is the only good news about them: they are running code with years of accumulated known vulnerabilities and no auto-update path that will ever reach them. A site that is three major versions behind did not get there by accident. It got there because auto-updates are off and nobody logs in.
The same API tells you what those installs are running underneath. 39.2% of WordPress sites are on a PHP version that is past end of life, with 17.4% still on PHP 7.4, which stopped receiving security fixes at the end of November 2022, and another 11.6% on PHP 8.1, which reached end of life on December 31, 2025. That is a separate problem from wp2shell, and it is a bigger one.
For context on scale: W3Techs’ survey today puts WordPress at 40.7% of all websites and 58.9% of sites whose CMS is identifiable. A percentage point of unpatched WordPress is an enormous number of actual businesses.
Meanwhile WordPress 7.1 “Mary Lou” shipped on August 19, three days ago, and is already on 43.4% of installs. The auto-update machinery genuinely works, and it moved most of the web onto a safe version inside a weekend. It just cannot reach the sites that have opted out of it, and those are disproportionately the ones nobody is watching.
What to actually do, in order
1. Find out what you are running. Log in and look at Dashboard, then Updates. Or open https://yoursite.com/wp-includes/version.php in a browser: if that file is readable you have a separate configuration problem, but it will tell you. If you are on 7.0.2, 6.9.5, 6.8.6, 7.1, or anything newer, you are patched. If you are on 6.9.0 through 6.9.4 or 7.0.0 through 7.0.1, you are still exposed right now and everything below is urgent rather than precautionary.
2. Confirm auto-updates are actually on. WordPress.org force-pushed this one, but the push only reaches installs where the auto-update system is enabled and functional. Plenty of hosts disable it, plenty of “hardened” setups turn it off, and file permissions or a DISALLOW_FILE_MODS constant in wp-config.php will silently prevent it. Under Dashboard, then Updates, WordPress states whether automatic updates for maintenance and security releases are enabled. If it does not say they are, that is your finding.
3. Check for persistence, if you were exposed during the window. This is the step that matters and the one that costs an hour.
- List every administrator account under Users and confirm you recognise all of them. Attackers picked innocuous names.
- Look at everything in
wp-content/cache/with a.phpextension. A cache directory should hold generated HTML, not PHP. - Compare your installed plugin list against the plugins you meant to install, including inactive ones.
- Grep your access logs for
POSTrequests to/wp-json/batch/v1or/?rest_route=/batch/v1. Wiz flags HTTP 207 Multi-Status responses to that endpoint as the reliable exploitation indicator, and notes user agent strings containingwp2shellorrezwp2shellfrom purpose-built tooling. - Check for files with modification timestamps clustered around your exposure window that you did not put there.
4. If you find anything, assume everything is compromised. Rotate the authentication keys and salts in wp-config.php, which logs every session out including the attacker’s. Rotate the database password. Force a password reset on every account. Then restore from a backup taken before the exposure window and reapply your changes on top of it, rather than trying to remove a webshell you have found and hoping it was the only one. It usually is not.
5. If your host manages this for you, get it in writing. Ask two specific questions rather than one general one: on what date did this site move to a patched version, and did you scan it for indicators of compromise afterwards. A managed host that force-patched you on July 18 did you a real favour. A host that patched you on July 18 and never looked for webshells has only done half the job, and it is worth knowing which one you have.
The strategic read, minus the sales pitch
We have written before that WordPress is a reasonable answer when the site is mostly content and the budget is tight, and we still think that. This does not change the recommendation. It changes one of the assumptions underneath it.
The old assumption was that WordPress core is the safe part and the plugins are the risk, so a site with few plugins is a low-maintenance site. wp2shell says the core has a large attack surface too, chiefly a REST API that is enabled by default and reachable without authentication, and that the surface can be exploited without any plugin’s help.
To be clear about what this does not mean: the plugin half of the risk did not go anywhere. Five days after this post first went up, a translation plugin on more than 400,000 sites turned out to be handing out administrator password reset links to unauthenticated visitors, at the same 9.8 severity. Core is now a risk as well as, not instead of. The practical consequence is that the maintenance cost of a WordPress site is not proportional to how many plugins it has. There is a fixed floor, and the floor is “someone has to be able to apply a core security release within roughly 24 hours, on a Friday in July.”
For a lot of small businesses that is a perfectly manageable commitment, and the auto-update system does it for free. For the ones running an install that somebody set up in 2019 and nobody has logged into since, it is a commitment they made without knowing it. If that describes a site you own, the honest fix is either to get it onto a host that does this for you or to move it to something with no admin panel and no database to inject into. We have opinions about the second option, but the first one is cheaper and works.
If you are not sure which situation you are in, send us the URL and we will tell you what version it is running and whether it looks like it has been touched. That takes about ten minutes and does not cost anything.
Sources
- WordPress 7.0.2 security release, WordPress.org, July 17, 2026
- CVE-2026-63030 and CVE-2026-60137, NVD
- CISA Known Exploited Vulnerabilities catalog, entries added July 21, 2026
- WordPress Exploitation Underway (CVE-2026-63030), SANS Internet Storm Center
- Exploitation in the Wild of wp2shell, Wiz
- WP2Shell WordPress Vulnerabilities Exploited in the Wild, SecurityWeek
- WordPress.org statistics API, retrieved August 22 and refreshed August 27, 2026
- PHP supported versions, php.net, for end-of-life dates
- W3Techs CMS usage survey, August 22, 2026