wp2shell: Unauthenticated WordPress Core RCE via REST API Batch-Route Confusion (CVE-2026-63030 + CVE-2026-60137)
Threat summary
On 17 July 2026, the WordPress core team shipped 6.8.6, 6.9.5, and 7.0.2 to fix a chain now widely tracked as wp2shell: an unauthenticated remote code execution path built from two separate bugs, CVE-2026-63030 (REST API batch-route confusion) and CVE-2026-60137 (SQL injection in WP_Query via the author__not_in parameter). Chained together, they let an anonymous, unauthenticated visitor reach code execution on a default WordPress installation — no plugin, no theme, no account required.
The chain was discovered by Adam Kues of Searchlight Cyber, whose team delayed publishing technical specifics past patch day specifically because of the install base at stake — WordPress powers well over 500 million sites.
Because the attack needs nothing beyond a stock install, and public proof-of-concept exploitation has been circulating since patch day, this is a same-day patch priority for any WordPress site the reader operates or manages, not a routine update.
What actually happened
WordPress's REST API exposes a batch endpoint, /wp-json/batch/v1, that lets a client bundle several sub-requests into a single call. Internally, the handler tracks those sub-requests using two parallel arrays. When one sub-request in the batch errors out, the two arrays fall out of sync by one position — a classic off-by-one confusion. The practical effect is that a later sub-request in the same batch gets processed under a different sub-request's routing and permission context than the one it actually declared.
That confusion (CVE-2026-63030) is the door. Walked through it, an attacker's input can reach the vulnerable code path behind CVE-2026-60137: unsanitised handling of the author__not_in parameter in WP_Query, which becomes a SQL injection. Chained, the two bugs take an anonymous HTTP request to arbitrary SQL execution and from there to remote code execution — hence the "wp2shell" name circulating in the security press.
Affected versions and patches
- CVE-2026-60137 (SQL injection): WordPress 6.8.0–6.8.5, 6.9.0–6.9.4, 7.0.0–7.0.1.
- CVE-2026-63030 (batch-route confusion, the piece that turns the SQLi into unauthenticated RCE): WordPress 6.9.0–6.9.4 and 7.0.0–7.0.1. The 6.8.x line is affected by the SQL injection but is not described by the official advisory as reachable through the full unauthenticated RCE chain.
- Fixed in: 6.8.6, 6.9.5, 7.0.2.
Given the severity, WordPress.org enabled forced automatic background updates for affected sites. That is a safety net, not a guarantee — hosts with auto-updates disabled, heavily customised deployments, or update mechanisms that silently fail will not be covered by it. Verify the installed version directly; do not assume the background update completed.
Exploitation status
Public write-ups describing the full mechanism, and working proof-of-concept code, appeared within days of the patch — a now-familiar pattern where patch diffing lets researchers (and attackers) reconstruct the vulnerable path quickly. Multiple outlets have reported exploitation attempts in the wild against unpatched sites shortly after disclosure. Treat any WordPress install still on an affected version as presumed-targeted, not merely presumed-vulnerable.
Immediate response checklist
- Confirm the running version on every WordPress instance you operate — dashboard, WP-CLI (
wp core version), or your fleet-management tooling. Do not rely on forced auto-update alone. - Update to 6.8.6, 6.9.5, or 7.0.2 (or later) immediately on anything still exposed.
- If you cannot patch immediately, block
/wp-json/batch/v1and the equivalent?rest_route=/batch/v1query-string form at your WAF or reverse proxy as a stopgap. This removes the entry point the chain depends on, at the cost of any legitimate integration that uses the batch endpoint. Searchlight Cyber's own advisory lists two further options for this gap: disabling the REST API entirely on sites that don't need it (e.g. via a "Disable WP REST API" style plugin), or gating the batch route behind authentication with a small compensating plugin. - Assume compromise is possible on any site that was on an affected version and internet-reachable between the vulnerability becoming exploitable and your patch landing. A successful chain can end in a webshell — patching closes the door but does not evict an attacker who already walked through it.
- Hunt for indicators of compromise before marking the incident closed: unexpected admin users, unfamiliar files in
wp-content/uploadsor theme/plugin directories, modifiedwp-config.phpor core files, unexpected scheduled tasks (wp_cron), and outbound connections from the web server process that don't match normal application behaviour. - Rotate secrets that a successful SQL injection could have exposed — database credentials, authentication salts/keys in
wp-config.php, and any API keys stored in the database — if compromise cannot be ruled out.
Detection guidance
Because the entry point is a single REST endpoint, log review is tractable even without deep WordPress instrumentation:
- Search access logs for
POSTrequests to/wp-json/batch/v1orrest_route=/batch/v1, especially with unusually large or malformed request bodies, or a high volume from a single source in a short window. - Look for batch payloads containing nested requests with SQL-metacharacter-heavy
author__not_invalues. - Correlate any hits with subsequent file-write activity or new admin-level user creation in the same timeframe.
None of this replaces patching — it narrows where to look if you suspect a site was exposed before the fix landed.
Frequently asked questions
Does this only affect sites with vulnerable plugins?
No. Both CVEs are in WordPress core, and the chain works against a stock installation with no third-party plugins or themes installed. Plugin exposure is a separate, additional concern — not a precondition here.
Is blocking the batch endpoint at the WAF a real fix?
It is a stopgap that removes the known entry point, useful when immediate patching isn't possible. It does not address the underlying SQL injection, and any other reachable path to the same WP_Query parameter would not be covered. Patch as soon as you can and treat the WAF rule as a bridge, not a destination.
We have forced auto-updates enabled — are we covered?
Likely, but verify. Auto-update can fail silently on constrained hosting, heavily modified core installs, or filesystem-permission issues. Confirm the version number directly rather than trusting the setting alone.
Evidence-led response with Eresus Guard
Eresus Guard brings DAST, SAST, SCA, and configuration checks into one evidence-led workflow. For an incident like wp2shell, that means being able to show — per asset — which WordPress version was running, when the patch landed, what compensating control (if any) was active in the gap, and what the compromise-hunt found. Explore the Eresus Guard workspace or plan a scoping call.
Sources
- wp2shell — Searchlight Cyber research disclosure
- WordPress 7.0.2 Security Release
- New wp2shell WordPress Core Flaw Lets Unauthenticated Attackers Run Code — The Hacker News
- WP2Shell WordPress Vulnerabilities Exploited in the Wild — SecurityWeek
- CVE-2026-63030: wp2shell — Rapid7
- WP2Shell Vulnerabilities: CVE-2026-60137 and CVE-2026-63030 — VulnCheck
- Two new high severity WordPress vulnerabilities, patch immediately — Help Net Security
Security Validation
Have you tested this risk in your own system?
Eresus Security delivers real exploit evidence through penetration testing, AI agent security, and red team operations.
Request a pilot testRelated Services