Twenty years of running WordPress in production teaches you two things about security releases. The boring ones you patch on Wednesday. The interesting ones you patch the moment they land, no matter what day it is. Last Friday’s 7.0.2 belongs firmly in the second bucket.
A pre-authentication remote code execution chain in WordPress core is the kind of story that used to be an annual event. It has now been years since the last one at this severity. The core security team turned around a coordinated patch on the same day the disclosure went public, backported it into three older branches, forced auto-updates across the estate, and reshuffled the 7.1 Beta cadence around it. That is what a mature governance layer looks like under fire.
Here is what actually shipped in 7.0.2, what the chain does under the hood, and the exact walk-through I would run across every WordPress site under management this week — including the ones you are sure auto-updated overnight.
What is actually new
WordPress 7.0.2 shipped on July 17, 2026, out of cycle, announced by John Blackbourn on the WordPress News blog. The release post is short and it is worth reading verbatim: two vulnerabilities, one critical and one high severity, both responsibly disclosed through the WordPress HackerOne programme, both patched simultaneously across every actively supported branch. The 7.0.2 version documentation lists exactly three files changed — wp-includes/rest-api/class-wp-rest-server.php, wp-includes/class-wp-query.php, and wp-includes/rest-api.php — and no packages revised. It is a targeted patch, not a maintenance release with security bundled in.
The critical issue is CVE-2026-63030, tracked as GHSA-ff9f-jf42-662q. In the advisory language it is “a REST API batch-route confusion weakness which, combined with an SQL injection issue, leads to Remote Code Execution.” The vulnerable entry point is WP_REST_Server::serve_batch_request_v1(), the handler behind the /wp/v2/batch/v1 endpoint that was introduced in WordPress 5.6 so that the block editor could pipeline multiple REST calls in one request. Reported by Adam Kues at Assetnote / Searchlight Cyber, it affects 6.9.0 through 6.9.4 and 7.0.0 through 7.0.1.
The high-severity issue is CVE-2026-60137, tracked as GHSA-fpp7-x2x2-2mjf — a facilitated SQL injection in the author__not_in parameter of WP_Query. When the parameter arrives as a string instead of an array, the is_array() sanitisation guard is skipped and the value flows straight into the NOT IN (...) clause. Reported as a team by TF1T, dtro, and haongo, it has been present since 6.8 and affects 6.8.0 through 6.8.5, 6.9.0 through 6.9.4, and 7.0.0 through 7.0.1.
On 6.9 and up the two chain together. The batch endpoint lets an unauthenticated attacker smuggle a request past capability checks, the author__not_in flaw becomes a controllable SQL injection sink, and the sink lets an attacker plant PHP that core then executes. That is the wp2shell name that has been travelling around the security community since Friday. The important part for site owners is not the nickname. The important part is that no login, no plugin, and no configuration change is required. A default WordPress install on an affected version was exploitable by an anonymous HTTP request.
Fixes shipped in parallel across every supported branch: 7.0.2 for the current major, 6.9.5 for the previous major (both chain components), 6.8.6 for the security-only branch (SQL injection only, the batch endpoint change that made the chain possible did not exist in 6.8), and 7.1 beta2 for the branch that was still in beta on release day. The 7.1 core page confirms that the beta cadence was reshuffled around the incident: the original July 22 Beta 2 became a re-cut Beta 2 on July 17 with the security fix, an extra Beta was added on July 29, and RC 1 stays on August 5 with GA still targeted for August 19. WordPress.org enabled forced auto-updates through the update API for every affected version. On paper, the vast majority of the estate is already on a patched build. On paper.
Why it matters for WordPress and WooCommerce people
A pre-authentication RCE in default core is the worst-case category. It bypasses everything you can plug in — no WAF rule can reliably match a shape-shifting batch payload, no rate limit protects against a single well-formed request, no 2FA sits in front of an anonymous endpoint. The only two defences that work are being on the patched version and being able to prove it.
The forced auto-update is genuinely good news and also the reason to look carefully. Auto-updates only fire on sites that (a) have WP_AUTO_UPDATE_CORE not explicitly disabled, (b) can write to their own core files, and (c) can reach api.wordpress.org from the server. Managed hosts patch the estate on their own path — WordPress.com, WP Engine, Kinsta, Pressable, Automattic-managed, Cloudways were all done by Saturday morning. Self-hosted sites on cheap shared hosting are the long tail. Any site with a customised wp-config.php that disables auto-updates for policy reasons is on you.
The WooCommerce angle is the same story with sharper edges. A store on an unpatched core is not just a leaked database. It is stored payment tokens, customer PII, order history, and, on the day the exploit lands, an attacker with the credentials to redirect payouts. Stripe for WooCommerce, PayPal Payments and the block Checkout stack all sit behind the same REST server that shipped the vulnerable batch handler. Every WooCommerce site on 6.9 or 7.0 that has not confirmed a patched version is treated as compromised until proven otherwise. That is the calm version of the framing.
The 7.1 cycle reshuffling matters mostly for release-lead teams and beta testers. The July developer roundup was written before Friday, so the schedule it prints is the old one. The current truth is that Beta 2 was re-cut on July 17, an extra beta was added, and any plugin author who was testing against Beta 1 needs to pull the re-cut Beta 2 before the July 29 window closes.
What I would do (or not do) about it
Four passes on every WordPress site under management, in this order, before the end of the week.
- Prove the version. Do not trust the dashboard number. Run
wp core versionon the server if you have SSH, or hit/wp-includes/version.phpand grep$wp_version. Anything below 7.0.2, 6.9.5, or 6.8.6 is not patched. WordPress 7.1 Beta 1 is not patched either — pull the re-cut Beta 2 or later. - Confirm auto-updates actually ran. Check
wp-content/upgrade/for a WordPress-7.0.2 folder timestamped July 17 or 18, look at Tools > Site Health > Info > WordPress for the current version, and if the site is behind a policy that disables auto-updates confirm that a human patched it. The most dangerous sites this week are the ones where nobody has looked because “auto-updates are on”. - Look for indicators of compromise on any site that was on 6.9 or 7.0 between the two Fridays. Search server logs for POST requests to
/wp-json/batch/v1or/index.php?rest_route=/batch/v1from before July 17, 15:00 UTC. Grep the filesystem for PHP files modified in the same window underwp-content/that you did not deploy. Checkwp_optionsfor unusual autoload entries,wp_usersfor new administrator accounts, and the object cache for planted scheduled events. - Update your client comms template. If you manage WordPress for anyone else, you need to have already sent the “we have confirmed your site is on the patched version” message. If you have not, send it now. Silence during a public RCE window is how agencies lose retainers.
Two things I would not do. Do not disable the REST API globally as a mitigation — the block editor, WooCommerce Store API, and every modern integration all depend on it, and you are patched anyway. Do not treat the 6.8.6 backport as a green light to stay on 6.8 forever; the core security team was clear that only the current major is actively supported and this cycle used up the last of that goodwill. Plan the 6.8 to 7.0.x migration on any site still on the old branch before the next incident, because there will be a next incident and the backport may not stretch that far next time.
The reassuring part of a bad Friday is watching the process work. Coordinated disclosure through HackerOne, same-day patch across four branches, forced updates through the release channel, a reshuffled beta cadence rather than a shipped-broken major. That is the WordPress governance layer earning its keep. Our job is to make sure the last mile — the site under a client’s domain — actually caught the update.
Last modified: July 19, 2026
United States / English
Slovensko / Slovenčina
Canada / Français
Türkiye / Türkçe