A public fix is a roadmap, and last week we said the quiet around wp2shell was a head start, not a reprieve. That head start is gone. One day after WordPress shipped the emergency Core release on July 17, the two flaws picked up CVE IDs, the full exploitation mechanism was published, and multiple working proof-of-concept exploits landed on GitHub. By July 19 the watchTowr team reported those exploits already circulating and the earliest live attacks starting to land. If you deferred the update on the assumption that no exploit existed yet, your threat model changed under you: you are now racing internet-wide scanners, not researchers sitting on a private writeup.
The compression here is the story. A pre-authentication remote code execution bug in default WordPress Core went from patched to weaponized in roughly a day. That is the planning number to carry forward: for an unauthenticated Core RCE, your patch service level has to be measured in hours, not the weekly maintenance window most teams run. The gap between "a fix is public" and "a working exploit is public" is now short enough that any deferral policy keyed to the old cadence is a policy to get hit.
What the newly public mechanism actually does
When we first wrote this up, the researchers at Searchlight Cyber were holding the technical detail back. Now it is out, and it is worth understanding because it dictates how you hunt. wp2shell is two bugs chained. The base is CVE-2026-60137, a SQL injection reached through WP_Query by way of its author__not_in argument. That argument expects an array; hand it a plain string and the validation waves it through, so attacker-controlled text lands in the query unescaped. On its own the flaw goes back to WordPress 6.8 and lets someone read password hashes straight out of the database.
The second bug, CVE-2026-63030, is the piece that removes the login requirement. WordPress lets the block editor fold several API calls into a single POST to /wp-json/batch/v1, and it keeps the bookkeeping for those folded calls in side-by-side lists. Force an error in one of them and the lists slip out of step by a single slot, which quietly reassigns a later call to a route handler it was never meant to reach. Once a call runs under the wrong handler, the endpoint allowlist stops meaning anything, and an anonymous request has a clean path down to the injection. No account, no plugin, no victim click. A stock install with no plugins at all is exploitable, which is what makes this a Core problem instead of a plugin one.
The object-cache "safety" is a trap, not a control
Our earlier post noted the one condition that narrows exposure: per Cloudflare, the code-execution path only opens on a site with no persistent object cache, and stock WordPress ships without one. Plenty of teams will read that, note that they run Redis or Memcached, and move the patch down their list. That is a mistake for two reasons.
First, the object cache only gates the code-execution step. The SQL injection underneath runs regardless of your cache, and it leaks password hashes. An attacker who cannot pop a shell on your cached site can still walk away with credentials to crack offline and replay, which is the follow-on the public PoCs are built to automate. Second, an object cache is a runtime dependency, not a security boundary. A dropped Redis connection, a failed Memcached lookup, a config change during a deploy: any of these can silently fall back to no cache, and the moment it does, the RCE path is open again. You do not want the thing standing between an anonymous request and code execution on your host to be whether a cache daemon happened to answer.
Patch first, then virtual-patch without breaking the editor
The fix is unambiguous: update to 6.9.5 or 7.0.2 now, and move sites on the 6.8 branch to 6.8.6 to close the injection. If you genuinely cannot patch in the next few hours, virtual-patching at the WAF buys time, and Cloudflare has already pushed rules to every plan. But be precise about the rule. Blanket-blocking the batch route at /wp-json/batch/v1, along with its ?rest_route=/batch/v1 form, also breaks the block editor, which uses the same batch endpoint to bundle saves into one request. The safer rule scopes the block to unauthenticated traffic: reject POSTs to the batch route that carry no valid logged-in cookie or REST nonce, and let authenticated editor traffic through. That keeps Gutenberg working while cutting off the anonymous path the exploit needs.
Now that the mechanism is public, hunt on it
Patching closes the hole. It does not tell you whether you were hit during the window between July 17 and the moment you updated, and with PoCs public since July 18 that window is where the risk lives. The good news is that a public mechanism is also a public detection signature. Look for anonymous POST requests hitting the batch route in your web server logs, whether they arrive as /wp-json/batch/v1 or the ?rest_route=/batch/v1 variant, especially any that predate your own upgrade. Pair that with file integrity monitoring for new or modified PHP under wp-content/uploads, wp-content, and wp-includes: a dropped web shell remains the most common post-exploitation artifact, and it is the same pattern we have watched play out across unpatched CMS campaigns all year. If hashes were pulled through the injection, rotate credentials and force password resets, because a patch does not evict an attacker who already has valid logins.
The uncomfortable part of wp2shell is how ordinary the timeline was. There was no zero-day surprise. The vendor did everything right, disclosed responsibly, and shipped a clean fix with a short embargo. The exploit still went public in a day, because a Core RCE with a public patch is one of the most valuable reverse-engineering targets on the internet. Treat the next one the same way: patch on the clock of the attacker, not the clock of your change-management calendar, and assume the hunt starts the moment the fix lands.