On July 17, 2026, WordPress pushed an emergency security release — version 7.0.2 — to patch two vulnerabilities that, when chained together, let any anonymous attacker run arbitrary code on a default WordPress installation. No plugins required. No authentication required. A single HTTP request. The exploit chain was nicknamed WP2Shell by the research team at Searchlight Cyber that discovered it, and the name stuck because the end result is exactly what it sounds like: a shell on your server, dropped by someone who never logged in.
By July 20, VulnCheck's canary network was observing active exploitation in the wild. More than two dozen unique proof-of-concept implementations were circulating. Cloudflare began blocking exploit attempts at scale. And if you run WordPress and have not updated since mid-July, your site is still a target.
The two bugs that made it work
WP2Shell is not a single flaw. It is two separate bugs that are mediocre on their own and devastating together.
The first is CVE-2026-60137, a SQL injection in the WP_Query class that has existed since WordPress 6.8. The author__not_in parameter is supposed to accept an array of user IDs. The code trusts that input and concatenates it directly into a SQL WHERE clause. When you send a string instead of an array, the type-checking falls apart and the raw value lands in the query. On its own, this injection is bounded — the routes that expose author__not_in require authentication, so an attacker would need to be logged in to reach it.
The second is CVE-2026-63030, a route confusion bug in the REST API batch endpoint (/wp-json/batch/v1), introduced in WordPress 6.9. This endpoint bundles multiple REST sub-requests into a single HTTP call. Internally, WordPress tracks those sub-requests in two parallel arrays: one for validation and permission checks, one for actual execution. The bug is a desync. When one sub-request triggers an error, the two arrays shift by one position. Sub-request N runs under the permission context of sub-request N-1. A public route acts as cover for a sensitive one.
Separately, these are the kind of bugs that get a CVE assignment and a quiet patch note. Together, they form an unauthenticated remote code execution chain with a CVSS score of 9.1 on the SQL injection component.
From injection to shell in one request
The attack flow is worth understanding because it is clever in a way that should make any developer uncomfortable.
The attacker sends a malformed batch request to /wp-json/batch/v1. The route confusion bug slips past permission checks, making the SQL injection reachable without authentication. But the injection does not just read data. It forges rows in wp_posts and wp_options — specifically, entries that look like legitimate oEmbed cache records and transients with predictable identifiers. WordPress then processes those forged entries as real content.
From there, the attacker creates a customize_changeset row tied to an administrator's user ID, which triggers a parse_request executed in admin context. The same batch request embeds a call to POST /wp/v2/users that creates a new administrator account, followed by a self-destructing plugin that runs system commands. The end result is a webshell, all from a single unauthenticated HTTP request that looks like any other REST API call in your access logs.
Who is affected
The full RCE chain works on WordPress 6.9.0 through 6.9.4 and 7.0.0 through 7.0.1. The SQL injection alone reaches back to 6.8.0 through 6.8.5, but without the route confusion bug it stays behind authentication. Versions before 6.8 are not affected at all.
At the time of disclosure, an estimated 400 million sites ran an affected version. Security consultant Daniel Card estimated that roughly 15 percent were actually vulnerable when accounting for managed hosts that patched proactively. That still leaves around 90 million sites at real risk.
WordPress.com, Pressable, WPVIP, WP.cloud, and most managed WordPress hosts pushed the patches automatically through WordPress's forced auto-update system. If your site is on one of those platforms, you are almost certainly fine. If you manage your own server, have disabled auto-updates, or run a site that was built and forgotten, you need to check now.
How to check if your site is safe
The fastest method is to look at your version number. Log into your WordPress admin dashboard and check the bottom-right corner. If you are running 6.9.5, 7.0.2, or later, you are patched. If you are running anything in the 6.9.0 to 7.0.1 range, assume you are vulnerable until proven otherwise.
You can also test whether the batch endpoint is exposed. Run this against your domain:
curl -s -o /dev/null -w "%{http_code}" https://your-site/wp-json/batch/v1
curl -s -o /dev/null -w "%{http_code}" "https://your-site/?rest_route=/batch/v1"
Any response other than 404 or 403 means the endpoint is reachable. Both routes need to be blocked — WAFs sometimes miss the query-string variant.
If you want to go deeper, security firms like Patchstack and Wordfence have published detection signatures and YARA rules for the exploit payloads. Running those against your access logs from July 17 onward will tell you if anyone has already tried the chain against your site.
What to do right now
Update. That is the one-sentence answer. WordPress 7.0.2 and 6.9.5 contain fixes for both CVEs. The update is a point release with no breaking changes, no PHP version bumps, and no deprecations. If you are still on 6.8, update to 6.8.6.
If you cannot update immediately — maybe you are waiting on a plugin compatibility check or a maintenance window — block access to /wp-json/batch/v1 at the web server level. Nginx or Apache rules to return 403 on that route will neutralize the exploit chain while you sort out the update. This is a bandage, not a fix, but it buys time.
After updating, audit your user list. The exploit creates new administrator accounts as part of its payload. If you see an admin user you do not recognize, or if your wp_users table has entries created between July 17 and your update date, treat the site as compromised. Change all passwords, rotate salts, and scan for uploaded webshells.
The real lesson
This is the third major WordPress core vulnerability in recent years that followed the same pattern: a patch ships, attackers reverse-engineer it, and then they scan the entire internet for sites that did not apply it. The vulnerability window between disclosure and mass exploitation has shrunk from weeks to hours.
WordPress is not the problem. A platform that powers 40 percent of the web will always be the biggest target, and the core team has been responsive about shipping fixes. The problem is the gap between when a fix is available and when it gets applied. Managed hosts close that gap automatically. Self-managed installations do not.
If you run WordPress and you do not have a process for applying security updates within 48 hours, WP2Shell is not the last time this will happen to you. The next exploit chain is already being built by someone who read the same patch notes the attackers did. The only question is whether your site will be updated when it drops.
Sources: VulnCheck WP2Shell Analysis, Flawfence CVE-2026-63030 Technical Breakdown, WordPress 7.0.2 Release Notes, J.M. Field Security Overview