TL;DR
It takes one unauthenticated request to turn a WordPress site into someone else's. Two core flaws chain into it: CVE-2026-60137, a SQL injection, and CVE-2026-63030, a REST batch route-confusion bug that hands an anonymous attacker access the first one was never supposed to allow. Apart, each looked manageable; together, nicknamed “wp2shell”, they turn an ordinary web request into full remote takeover of any WordPress 6.9.x or 7.0.x site. WordPress has patched it, but working exploits are already circulating, and attacks have begun, so exposed sites should mitigate now and patch immediately.
Most Popular CMS on the Internet
WordPress is the content management system that runs a very large share of the world’s websites: blogs, news sites, storefronts, and corporate marketing sites all sit on the same core codebase. At its center is a query builder called WP_Query, the component that turns a request for content into the actual database lookups behind it.
Almost everything a WordPress site knows flows through that database: user accounts and password hashes, secrets and API keys stored by plugins, customer records, and the site’s own content. When an attacker can reach the database directly or run their own code on the server, none of that data is safe, and the site itself can be rewritten.
Because WordPress is installed on so many internet-facing hosts, a pre-authentication flaw in core is not a niche problem. It is a flaw that applies, all at once, to a very large population of exposed sites.
The Findings at a Glance
- CVE-2026-60137: SQL injection in author__not_in of WP_Query. The
author__not_inparameter is meant to hold a list of numeric author IDs to exclude. The sanitization assumes it is always a list; pass a string instead and the raw value is spliced straight into a SQLNOT IN (...)clause. On its own it is gated: WordPress core restricts the vulnerable path to authenticated users through a blocklist, so it is not anonymously reachable until CVE-2026-63030 bypasses that blocklist. - CVE-2026-63030: REST batch route confusion (auth-bypass primitive). The unauthenticated
/wp-json/batch/v1endpoint lets a caller pack several sub-requests into one call. A parallel-array desync knocks the handler list and the validation list out of step, so a sub-request that should have failed its own permission check runs under a handler that passed the check. No authentication required to trigger this one.
Chained together (“wp2shell”), on WordPress 6.9+, they are pre-auth remote code execution. An anonymous attacker uses the route confusion to slip attacker-controlled input into WP_Query, drives the SQL injection, and reaches code execution and full site takeover.
.webp)
Fixed in WordPress 6.8.6, 6.9.5, and 7.0.2, all released 2026-07-17. As of 2026-07-19, the chain is not in the CISA KEV catalog, but multiple working PoCs are already public, and at least one vendor has reported early exploitation attempts, so expect widespread scanning and treat the patch window as closing fast.
Affecting 6.9.0 onward, CVE-2026-63030, the REST batch route-confusion bug, was reported by Adam Kues of Searchlight Cyber. Interestingly, the underlying SQL injection in WP_Query (CVE-2026-60137) was reported by a different team. WordPress shipped coordinated fixes across all three affected branches on 2026-07-17.
How Miggo Helps
The fix is the WordPress core update. But updates are never instant across a real estate of sites, and even forced auto-updates do not reach frozen container images, pinned versions, disabled-auto-update installs, managed or abandoned deployments, or WordPress embedded inside other products. Those are the sites still exposed the day after disclosure, and they are exactly what a virtual patch is built for.
Miggo WAF Copilot analyzed the wp2shell chain and generated a ready-to-deploy WAF rule that blocks the wp2shell request pattern before it reaches the app. The rule anchors on the chain’s delivery path, handling different methods of exploitation.

Alongside the virtual patch, the core actions still apply:
- Patch. Update WordPress core to the fixed release for your branch (6.8.6, 6.9.5, or 7.0.2). The virtual patch buys time; it does not replace the update.
- Rotate exposed secrets. SQL injection can read database contents, and the RCE chain can compromise the host, so treat any credentials or secrets reachable through the affected queries or the site environment as potentially leaked. Patching removes the vector; it does not invalidate a secret that was already read.
Conclusion
Neither of these bugs alone is exotic. Both bugs were found, triaged, and filed as manageable: one a SQL injection you couldn’t reach without a login, the other a routing quirk with no obvious teeth. Two reasonable calls, each correct right up until someone set them next to each other.
That is the pattern worth keeping. Severity is a judgment about reach, and reach is the one thing a single-CVE view can’t see. We rate flaws one at a time; attackers assemble them. And the cost of that assembly is falling: the same AI-assisted analysis that reads patch diffs for defenders also reads them for everyone else, which is why the gap from a public patch to a working exploit was hours, not weeks.
Then there is the part no response can fix. WordPress did everything right and forced the update, and a huge tail of sites stayed exposed anyway: frozen images, pinned versions, disabled updaters, abandoned installs, WordPress buried inside other products. A patch existing is not a patch arriving, and for that tail the gap never closes. That gap is what Miggo works on: when a chain like this lands, the question isn’t how fast you can patch, it’s what stands in front of the sites you can’t. A mitigation in the request path, generated from the advisory the day it drops, turns a disclosure from a race you’re losing into a window you can hold.
Check your WordPress exposure
Running WordPress and want to verify your exposure, or see how Miggo protects your runtime between patch cycles? Request a demo.






