Security

wp2shell: The WordPress Core Flaw That Lets Anyone Run Code on Your Site

wp2shell is a chained WordPress core vulnerability, CVE-2026-63030 and CVE-2026-60137, that lets an unauthenticated attacker reach remote code execution through the REST API batch endpoint on a default install, patched in WordPress 6.9.5 and 7.0.2 on July 17, 2026 and added to the CISA Known Exploited Vulnerabilities catalog on July 21.

wp2shell is the name given to a pair of chained vulnerabilities in WordPress core that together let an unauthenticated attacker run code on a stock WordPress site. Not a plugin. Not a misconfigured theme. Core, on a default install, with no login and no user interaction. WordPress patched it on July 17, 2026, attackers had working exploits within roughly 48 hours, and both bugs were added to CISA’s Known Exploited Vulnerabilities catalog on July 21, which is the formal way of saying this is being used against real sites right now.

If you run a WordPress site, the only three things that matter are: which version you are on, whether you have patched, and whether someone got in before you did. That last one is the part most coverage skips, and it is the reason this post exists.

The short version

WordPress 6.9.0 through 6.9.4 and 7.0.0 through 7.0.1 are affected. The fixes are in WordPress 6.9.5 and 7.0.2, released July 17, 2026, and the fix is also in WordPress 7.1 Beta 2. Versions earlier than 6.9 are not affected by the critical half of the chain.

WordPress maintainers took the unusual step of forcing updates to installations with automatic updates enabled, which is why most sites were protected without anyone touching them. That is a genuine success story for automatic updates, and it is also exactly why the remaining exposed sites are the ones that most need attention: they are disproportionately the installs where auto-updates were disabled, often deliberately, on managed or customised setups.

What wp2shell actually is

The name is slightly misleading, because wp2shell is two separate bugs. Neither one is sufficient on its own. Chained, they take an anonymous HTTP request all the way to code execution.

CVE-2026-63030 is the critical one, a logic flaw in the WordPress REST API batch processor at /wp-json/batch/v1. The batch endpoint validates sub-requests in one loop and executes them in another. When URL parsing fails on a sub-request path, the error gets pushed into the validation array but not into the matches array, and the two arrays fall out of sync. From that point on, every subsequent request in the batch dispatches under the wrong handler. It is a bookkeeping mistake with severe consequences: the request you are running is no longer the request that was checked.

CVE-2026-60137 is a SQL injection in the author__not_in parameter of the posts endpoint. When that parameter arrives as a plain string rather than an array, it gets interpolated straight into raw SQL. Normally parameter validation stops that from ever happening. But the batch desynchronisation above bypasses the validation, and a recursive batch call gets around the usual restrictions on GET requests, producing a pre-authentication UNION-based SQL injection.

Put together, the escalation path runs through WordPress internals to create an administrator account. The attacker then logs in as that administrator and uploads a malicious plugin, which is code execution. Researchers at Searchlight Cyber, who found and disclosed the chain, have published the full technical breakdown.

One nuance worth knowing if you are assessing your own risk: Cloudflare reported that the vulnerable code path is reachable when a persistent object cache is not in use. That does not make an object cache a security control, and it should not change your patching urgency, but it is a real detail in how exploitability varies across hosting setups.

What attackers are doing with it

This did not stay theoretical. Public proof-of-concept exploits surfaced within days, and security firms tracking the activity have logged large volumes of scanning and exploitation attempts, running from simple probes through to full takeover attempts.

What lands on a compromised site is a webshell. Reported payloads range from one-line PHP backdoors to feature-rich obfuscated shells dressed up to look like legitimate plugins. That disguise matters for your response, because a quick glance at the plugins list will not necessarily reveal anything odd. A shell named to blend in with real plugins is designed precisely to survive a casual audit.

The practical consequence is that patching closes the door but does not evict anyone already inside. An administrator account created before you updated still works after you update. A webshell dropped on disk still executes.

What to do right now

Work through this in order.

  • Check your version. In wp-admin, look at Dashboard then Updates, or check the footer of the admin screen. If you are on 6.9.5, 7.0.2, or later, the core flaw is patched. If you are on 6.9.0 to 6.9.4 or 7.0.0 to 7.0.1, you are exposed and should update immediately.
  • Update, even if you think auto-updates handled it. Verify rather than assume. Forced updates covered installations with automatic updates enabled, but managed hosts, staged deployments, and version-controlled sites frequently have that turned off.
  • If you cannot patch immediately, block the endpoint. The interim mitigation is to block /wp-json/batch/v1 and the equivalent ?rest_route=/batch/v1 at your web application firewall, or disable anonymous REST API access. Treat this as a stopgap measure while you arrange the update, not as a fix.
  • Then assume you might have been hit, and check. This is the step that gets skipped.

Checking whether you were compromised

Patching a site that was already breached leaves you with a patched, still-compromised site. Given that exploitation began within about two days of the patch, any site that stayed unpatched for even a short window afterward is worth examining rather than assuming clean.

Look for these specifically:

  • Unfamiliar administrator accounts. The exploit chain works by creating one. Review your user list for accounts you do not recognise, and check the registration dates against the exposure window.
  • Plugins you did not install. Compare the plugins directory against what you expect to be there, including plugins that look plausible but that nobody on your team remembers adding.
  • Unexpected PHP files. Especially in uploads directories, which should never contain executable PHP. File-integrity comparison against a known-good copy of core is far more reliable than visual inspection.
  • Anomalous requests to the batch endpoint in your access logs. Requests to /wp-json/batch/v1 or ?rest_route=/batch/v1 around and after July 17 are the signature to search for.

If you find evidence of compromise, patching is not the end of the work. Rotate credentials, review what the account had access to, and follow a structured process rather than improvising, which is what our guide to building a data breach response plan is for. A clean restore from a backup taken before the exposure window is often faster and more trustworthy than trying to clean a compromised install by hand, which is one of the practical arguments in our piece on WordPress backup security.

The uncomfortable lessons

Three things about this incident are worth carrying forward beyond the immediate patching scramble.

The REST API is attack surface, and it is on by default. WordPress ships with REST endpoints enabled, and the batch route exists to let clients bundle requests efficiently. That is a reasonable feature. But the flaw here was not exotic cryptography or memory corruption; it was two arrays falling out of step in a validation loop. Complexity in a default-enabled interface is where this class of bug lives, and the broader lesson applies well beyond WordPress, as we discussed in the context of securing the WordPress 7.0 Connectors API.

Automatic updates did their job. It is worth saying plainly, because auto-updates are often treated as a risk to be managed rather than a control that works. The forced-update mechanism is the single biggest reason this was not far worse. If your organization disables automatic core updates as a matter of policy, this incident is a reasonable prompt to revisit that policy, or at least to pair it with a monitored process that patches critical core releases within hours rather than weeks. Managed hosting that handles this for you has real value here, as our comparison of managed WordPress hosts covers.

The discovery method is a signal about what comes next. Searchlight Cyber’s own writeup describes finding this bug with the help of a frontier AI model, specifically GPT-5.6. That is worth sitting with. A pre-authentication remote code execution chain in the core of the world’s most widely deployed CMS, of the kind that commands very large sums from exploit brokers, was surfaced with AI assistance. The same capability is available to people who will not be filing responsible disclosures. Expect the discovery rate for this class of bug to rise, and plan your patching cadence on the assumption that the window between a fix shipping and a working exploit existing will keep shrinking. Forty-eight hours was this round.

Frequently Asked Questions

What is wp2shell?

wp2shell is the name for two chained WordPress core vulnerabilities, CVE-2026-63030 and CVE-2026-60137, that together allow an unauthenticated attacker to execute code on a WordPress site. CVE-2026-63030 is a logic flaw in the REST API batch processor; CVE-2026-60137 is a SQL injection. Neither is sufficient alone, but chained they escalate to remote code execution on a default install with no plugins and no login required.

Which WordPress versions are affected?

WordPress 6.9.0 through 6.9.4 and 7.0.0 through 7.0.1 are affected. The fixes shipped in WordPress 6.9.5 and 7.0.2 on July 17, 2026, and the fix is also included in WordPress 7.1 Beta 2. Versions earlier than 6.9 are not affected by CVE-2026-63030.

How do I know if my site is patched?

Check your WordPress version in wp-admin under Dashboard then Updates, or in the admin footer. If you are on 6.9.5, 7.0.2, or later, the core flaw is fixed. Verify rather than assume, because while WordPress forced updates to installations with automatic updates enabled, many managed, staged, or version-controlled deployments have automatic updates turned off.

Is wp2shell being actively exploited?

Yes. Public proof-of-concept exploits appeared within days of the patch, security firms have logged large volumes of scanning and exploitation attempts, and both CVEs were added to CISA’s Known Exploited Vulnerabilities catalog on July 21, 2026. Observed attacks install PHP webshells, including obfuscated ones disguised as legitimate plugins.

I patched. Am I safe?

Patching prevents new exploitation but does not remove an attacker who already got in. The exploit chain creates an administrator account and typically drops a webshell, and both survive an update. If your site was unpatched at any point after July 17, check for unfamiliar admin accounts, plugins you did not install, unexpected PHP files in uploads directories, and requests to the batch endpoint in your access logs.

What can I do if I cannot update immediately?

As a temporary measure, block the /wp-json/batch/v1 endpoint and the ?rest_route=/batch/v1 equivalent at a web application firewall, or disable anonymous REST API access. Treat this as a stopgap while you arrange the update. It reduces exposure to this specific chain but is not a substitute for patching core.

Does disabling the REST API fix it?

Restricting anonymous REST API access blocks the specific route this chain abuses, which is why it works as an interim mitigation. But the REST API underpins a great deal of modern WordPress functionality, including the block editor and many plugins, so disabling it broadly can break your site in ways that are hard to predict. Patch instead, and use endpoint blocking only to bridge the gap.

Why did this get exploited so quickly?

Security patches are themselves a roadmap. Once a fix ships, attackers can compare the patched and unpatched code to locate the flaw, which is why the window between a patch and a working exploit is often measured in days. In this case it was roughly 48 hours, and full technical details plus multiple public proof-of-concept exploits followed within a week.

Digital Matters

Security Desk