20 July 2026 CVE .

WordPress wp2shell Critical Vulnerabilities: Exploitation Risks, Mitigation Strategies

TL;DR: unauthenticated remote code execution on a default install. A patch shipped late on a Friday, public proof-of-concept code overnight, and still no CISA KEV listing: the anatomy of an exposure window of at least three days.

On 17 July 2026, WordPress shipped three emergency releases and triggered forced auto-updates worldwide. The flaw, named wp2shell, lets an anonymous attacker reach code execution on a default installation by chaining a REST API route confusion vulnerability (CVE-2026-63030) with a SQL injection (CVE-2026-60137).

DO THIS IMMEDIATELY

If you run WordPress, confirm the installed version is 7.0.2, 6.9.5 or 6.8.6 (or later). Do not assume the forced update worked. Check the version on every instance, across all of your WordPress sites.

Key Takeaways

  • The flaw: wp2shell chains two vulnerabilities in WordPress core (CVE-2026-63030 and CVE-2026-60137) to achieve pre-auth remote code execution, with no third-party plugin and no user interaction.

  • Affected versions:

    • Vulnerable: 6.9.0 to 6.9.4 and 7.0.0 to 7.0.1

    • Fixes: 7.0.2, 6.9.5, 6.8.6 (since 17 July 2026)

  • Release timing was poorly chosen. The WordPress team pushed a critical patch on a Friday afternoon US time, Friday evening in Europe, knowing the fix would be analysed to build a working exploit. Security teams were left dealing with it over a weekend.

  • Forced auto-updates are not enough. They do not reach installs that disabled or blocked them. Verify what is actually running.

  • Exposure window: several days between the patch and any CISA listing, while public proof-of-concept code had been circulating since the early hours of Saturday.

  • Patching is not the end. Because working exploit code appeared so quickly, hunting for indicators of compromise across the exposure window is essential.

wp2shell disclosure timeline

When What Source
Fri 17 · 18:00 CEST WordPress ships 7.0.2, 6.9.5 and 6.8.6, and triggers forced auto-updates. wordpress.org
Fri 17 GitHub security advisories GHSA-ff9f-jf42-662q and GHSA-fpp7-x2x2-2mjf are published. GHSA-ff9f · GHSA-fpp7
Fri 17 · 17:03 UTC Cloudflare deploys two WAF rules. blog.cloudflare.com
Fri 17 · 20:53 CEST WordPress announces the fix on its public channels. Official WordPress channels
Sat 18 · ~01:00 CEST First exploitation signals reported, and a public proof of concept appears. Deliberately not linked
Sat 18 · 10:00 CEST Integrated into Patrowl, and all customers scanned.
Sat 18 Security vendors publish diverging assessments of the exploitation status.
Mon 20 · 10:20 CEST The French national CERT (CERT-FR) publishes alert CERTFR-2026-ALE-007. cert.ssi.gouv.fr
Tue 21 CVE-2026-63030 still does not appear in the CISA KEV catalog. cisa.gov

How the wp2shell exploitation chain works

The name suggests a single defect. The reality is different: two independent weaknesses that, combined, produce code execution.

Route confusion (CVE-2026-63030)

WordPress 6.9 introduced a path in its REST API (/wp-json/batch/v1 or ?rest_route=/batch/v1) that allows several requests to be sent in a single API call, to improve performance. CVE-2026-63030 is a route confusion issue on that path which allows the authorization check to be bypassed.

SQL injection (CVE-2026-60137)

CVE-2026-60137 is an authenticated SQL injection in the author_notin parameter of WP_Query.

Chaining the two

The route confusion bypasses the authorization check, making the SQL injection exploitable without authentication. From the SQL injection, an attacker can extract data from the database, such as the administrator password hash for offline cracking, then take control of the site by dropping a backdoor such as a webshell.

AN EXPLOITABILITY CONDITION THAT IS OFTEN LEFT OUT

Cloudflare reports that the vulnerable path for CVE-2026-63030 is reachable when a persistent object cache is not in use. A site running Redis or Memcached may not expose the same path, but the SQL injection still needs fixin

The disagreement over severity ratings

No surprise here, and it is a point we keep making: steering remediation purely by CVSS score and by catalogs such as the CISA KEV is not enough. Scores have to be combined and then assessed against real-world exploitation and actual business impact.

WordPress versions affected by wp2shell

Branch Affected versions Exposure Fixed version
7.0 7.0.0 to 7.0.1 Full wp2shell chain 7.0.2
6.9 6.9.0 to 6.9.4 Full wp2shell chain 6.9.5
6.8 6.8.0 to 6.8.5 SQL injection only 6.8.6
7.1 beta Beta releases Fix included 7.1 Beta 2
Earlier than 6.8 Not affected

WordPress powers roughly 41.5% to 41.9% of all websites. An unauthenticated flaw in the CMS core instantly turns a massive user base into automated targets.

THE MOST COMMON BLIND SPOT

The risk lies in forgotten instances: staging environments, campaign sites, subsidiary blogs, legacy subdomains, and QA environments left online.

At Patrowl: two checks rather than one

Our priority was to alert customers as fast as possible. Every minute counted. So we ran a first check that closely analysed the actual WordPress versions in place, which bought us the few precious minutes needed to integrate full exploitation code capable of confirming the vulnerabilities.

That first check, already partly in place, detected WordPress versions using our EASM data, going well beyond the usual <meta name="generator"> tag and /readme.html file.

The second check, added a few minutes later, chained both vulnerabilities to confirm which assets were genuinely vulnerable.

How to fix wp2shell: updates and workarounds

1. Verify the version actually installed

Forced auto-updates do not reach every install. Check the version on each instance.

Ways to check the version:

  • From the WordPress dashboard: the Updates section.

  • From the page source (if not stripped): right click, View page source, then look for <meta name="generator" content="WordPress X.X.X" />. Note that this tag is routinely removed or spoofed on hardened sites.

  • From the command line:

wp core version --path=/var/www/monsite

Via the page source code (if not hidden):

  • Right-click → "View Page Source"

  • Search for the <meta name="generator" content="WordPress X.X.X" /> tag.

Command line:

  • By reading wp-includes/version.php

An instance is up to date if it reports 7.0.2, 6.9.5, 6.8.6 or later.

2. If you cannot patch immediately

Temporary workarounds exist to block unauthenticated access to the SQL injection.

THE CLASSIC MISTAKE

Do not filter /wp-json alone. The endpoint is also reachable through ?rest_route=/batch/v1.

Apache example:

<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{REQUEST_URI} ^/wp-json/batch/v1/?$ [NC,OR]
RewriteCond %{QUERY_STRING} (^|&)rest_route=/batch/v1/?(&|$) [NC]
RewriteRule ^ - [F,L]
</IfModule>

Cloudflare deployed two WAF rules on 17 July at 17:03 UTC. Confirm they are enabled and that your own rule overrides have not neutralised them.

A DISSENTING VIEW

Some analyses advise against relying on workarounds at all. Cloudflare frames its rules as temporary exposure reduction. Both positions converge on the essentials: a workaround buys time, it fixes nothing.

3. Do not confuse affected version with real exposure

An asset reporting a vulnerable version is not necessarily exploitable. A WAF, a persistent object cache, a restricted endpoint or a back-ported fix can all reduce the actual risk.

Check whether your WordPress site was compromised

Patching closes the door. It tells you nothing about the period before it. Any instance that went unpatched through Saturday and Sunday sat exposed while public exploit code was already circulating, so that window needs auditing.

Start with:

  • Administrator accounts: look for recently created accounts or unexplained privilege escalations.

  • Plugins and files: look for unknown plugins and PHP files in upload directories.

  • Database: look for abnormal rows in wpposts or wpoptions.

  • Web server logs: review requests to the vulnerable API path.

  • Change the administrator password: not strictly necessary if the site was not compromised, but sound security hygiene either way.

# Requests to the batch endpoint
grep -E "batch/v1" /var/log/nginx/access.log*

# PHP files recently created in uploads
find /var/www/mysite/wp-content/uploads -name "*.php" -mtime -7 -ls

# Administrator accounts
wp user list --role=administrator --fields=ID,user_login,user_registered

IF YOU FIND ANYTHING

A confirmed compromise means treating the administrator password as leaked:

  • Rotate credentials

  • Invalidate sessions

  • Change the salt keys

If a webshell could have been dropped, reinstalling from a clean source is the safer path. If you hold recent backups, a full restore is worth considering.

What wp2shell reveals about your remediation process

Beyond the WordPress case itself, this episode is a live test of your vulnerability management process. The question is not "did you patch", but "what would have triggered your emergency procedure, and when".

If your escalation depends on a CISA KEV listing or a CERT-FR advisory, you went through an entire weekend with no signal, while the patch, the maintainer advisory and public proof-of-concept code all existed. Those references are legitimate and valuable, but by design they rest on evidence consolidation, which takes time. Treating them as your only trigger means indexing your response time on the slowest link in the chain.

If your escalation depends on the CVSS score, you may have downgraded to "high" a flaw the maintainer rated critical, because scoring bodies disagreed on the same vulnerability.

If it depends on your vulnerability scanner, the question becomes how quickly the signature was integrated, and how often you scan. A weekly scan might have given you a signal, but too late. A monthly one would not have helped at all.

THE EARLIEST TRIGGER AVAILABLE

The fastest and best-qualified information was the GitHub advisory, published the same day, carrying the "critical" rating, the affected versions and the fixed version.

Wp2shell: Key Takeaways

wp2shell will be remembered as a textbook case, less for its technical sophistication than for its timeline. The vendor moved fast and hard. Perhaps too fast.

And yet an organisation waiting for an official signal spent a full weekend unaware that an unauthenticated remote code execution had been fixed and was being exploited in the wild.

The lesson: you need to be able to watch vendor advisories, GitHub channels, social media and blogs, but also to maintain an accurate inventory and check a version across an entire estate in minutes. That is what turns these three days of waiting into an evening of work.

FAQ

Is my site vulnerable?
If you run WordPress 6.9.0 to 6.9.4 or 7.0.0 to 7.0.1, you are exposed to the full chain. On 6.8.0 to 6.8.5, only the SQL injection applies. Versions 6.9.5, 7.0.2, 6.8.6 and later are fixed.
Didn't the forced auto-updates already protect me?
Probably, but not certainly. The mechanism does not reach installs that have disabled or blocked auto-updates. Check the version on every instance.
Is a third-party plugin required to be exposed?
No. A default install, with no plugin, no special configuration and no valid account, is reachable.
Is the flaw being exploited in the wild?
Public proof-of-concept code is circulating, which warrants emergency treatment regardless of confirmed exploitation status.
Does a persistent object cache protect me?
Cloudflare reports that the vulnerable path for CVE-2026-63030 is reachable when a persistent object cache is not in use. Treat that as a prioritisation factor, not an exemption. The SQL injection still needs fixing.
Is blocking the endpoint at the WAF enough?
No. It buys time, it is not a fix. It has to cover both access paths, including the ?rest_route=/batch/v1 variant, and it may break legitimate integrations.
Why do severity ratings differ between sources?
Because several bodies can score the same vulnerability independently, with different assumptions about vector and impact. When in doubt, act on the highest rating.
I have applied the patch. Do I need to go further?
Yes. A patch applied today tells you nothing about the period before it. Look for recently created admin accounts, unknown plugins and PHP files, abnormal rows in wp_posts or wp_options, and requests to the batch endpoint.
What should I do if I find a compromise?
Treat the administrator password as disclosed. Rotate credentials, invalidate sessions, change the salt keys. If a webshell could have been dropped, reinstalling from a clean source beats cleaning up.
How do we get alerted earlier next time?
By not making consolidated references your only escalation trigger. Maintainer advisories land much earlier. That only helps if you keep an up-to-date inventory of the products you expose.