DEV Community

Zahid Rasheed
Zahid Rasheed

Posted on • Originally published at xuro.net

WP2Shell (CVE-2026-63030): Is Your WordPress Site Already Hacked? How to Check and Fix It

If you run a WordPress site, stop what you're doing and check your version number. There is a live, unauthenticated remote-code-execution flaw in WordPress core itself — no vulnerable plugin required — and attackers have been mass-exploiting it since July 18. It's been nicknamed WP2Shell, and unlike most "critical" advisories that need a specific plugin or a logged-in account, this one lets a complete stranger run code on a stock WordPress install from anywhere on the internet.

I've cleaned north of 400 hacked WordPress sites over 15 years, and the pattern with a bug like this is always the same: the sites that get hit aren't the ones with weak passwords or pirated themes. They're ordinary, well-maintained sites whose owners hadn't heard the news yet and were three days behind on an update. So let's make sure that's not you.

The 30-Second Version

  • What it is: Two chained WordPress core vulnerabilities — CVE-2026-63030 (CVSS 9.8, a route-confusion bug in the REST API's /wp-json/batch/v1 endpoint) and CVE-2026-60137 (CVSS 9.1, a SQL injection in WP_Query). Chained together they give an unauthenticated attacker full remote code execution.
  • Are you affected? Yes, if you're running WordPress 6.9.0–6.9.4 or 7.0.0–7.0.1.
  • The fix: Update to WordPress 6.9.5 or 7.0.2 immediately (released July 17, 2026). WordPress.org pushed forced auto-updates for affected sites — but you must confirm yours actually applied.
  • Already breached? Attackers are planting hidden admin accounts and webshells. Scan your site free to check — the cleanup steps are further down.

What WP2Shell Actually Does

Most WordPress attacks need a foothold — a vulnerable plugin, a leaked password, a poisoned theme. WP2Shell needs none of that. It abuses two flaws that ship in WordPress core:

The first, CVE-2026-63030, is a route-confusion bug in the REST API's batch-processing endpoint (/wp-json/batch/v1), which is enabled by default. It lets an attacker smuggle input past the normal permission checks. That smuggled input feeds the second flaw, CVE-2026-60137, a SQL injection in WordPress's core WP_Query (via the author__not_in parameter).

Chained, the two turn into a full unauthenticated compromise: the attacker forges a database record, writes to WordPress's oEmbed cache, and from there escalates into a rogue administrator account and a webshell plugin. Once that webshell lands, they own the server — they can serve spam, inject malware into every page, steal customer data from a WooCommerce store, or pivot to other sites on the same hosting account.

The scale is what makes this ugly. Security firm Wiz found that roughly 60% of organizations running WordPress had at least one vulnerable instance when the flaws were disclosed, and about a quarter were exposing a vulnerable server directly to the internet. Public proof-of-concept exploit code is already circulating, which is why scanning and exploitation attempts spiked within a day of disclosure.

Am I Affected? (Check in 60 Seconds)

You're vulnerable if your site runs any of these versions:

  • WordPress 6.9.0, 6.9.1, 6.9.2, 6.9.3, or 6.9.4
  • WordPress 7.0.0 or 7.0.1

To find your version, log into wp-admin and look at the bottom-right of the dashboard, or check Dashboard → Updates. If you can't log in, you can often see it in your page source (though many sites hide it) or ask your host.

If you're on 6.9.5, 7.0.2, or newer, you're patched. If you're on anything older than 6.9.0, you're not affected by this specific chain — but you're dangerously behind on other security fixes and should update anyway.

How to Fix It — Right Now

1. Update WordPress core. Go to Dashboard → Updates and install the latest version (6.9.5 on the 6.9 branch, or 7.0.2 on the 7.0 branch). If you manage the server, you can also update via WP-CLI:

wp core update
wp core version
Enter fullscreen mode Exit fullscreen mode

Confirm the second command reports 6.9.5 / 7.0.2 or higher.

2. Verify the auto-update actually applied. WordPress.org enabled forced automatic updates for affected sites because of how severe this is — but forced updates can silently fail on sites with file-permission locks, disabled cron, or DISALLOW_FILE_MODS set. Don't assume. Log in and check the version number yourself.

3. If you genuinely can't update immediately, ask your host or a WAF (Cloudflare, Wordfence, Sucuri) to block requests to /wp-json/batch/v1 as a stopgap. This is a band-aid, not a fix — patch as soon as you can.

Patching stops future exploitation. It does not remove an attacker who already got in before you updated. That's the part most people miss.

Am I Already Hacked? How to Tell

Because this bug was exploited in the wild for days before many sites updated, a clean version number today doesn't guarantee you weren't hit yesterday. Warning signs to look for:

  • Administrator accounts you don't recognize (Users → All Users — sort by role and date).
  • Plugins you never installed, especially ones with generic names, that are active but not in the plugin directory.
  • Unexpected files in wp-content/, wp-includes/, or the web root — particularly .php files with random names or recent modification dates.
  • Requests to /wp-json/batch/v1 in your access logs around or after July 17.
  • Spam pages, redirects, or "This site may be hacked" warnings in Google search results.
  • Your host suspending the account or flagging outbound spam.

If any of that rings true — or you simply want peace of mind — the fastest first check is to run our free hacked-site scanner. It checks your site against malware and phishing blocklists, inspects TLS and security headers, and flags the tell-tale signs of a compromise from the outside, no login or plugin install required.

For a deeper look, WordPress's security team and several vendors have released an official wp2shell compromise-scanner plugin and browser extension that check specifically for this attack's fingerprints.

If You're Compromised: Don't Just Delete and Move On

Here's the mistake I see constantly. Someone finds one bad file, deletes it, updates WordPress, and calls it done. Two weeks later the site reinfects, because the attacker left a second backdoor — a hidden admin, a modified wp-config.php, a cron job, a poisoned .htaccess — that never got touched. With WP2Shell specifically, the whole point of the attack is to plant persistence, so a partial cleanup almost always fails.

So here's what a proper cleanup actually looks like. Before you touch anything, take a full backup of both the files and the database — you want a forensic copy in case you need to trace what happened or something goes wrong mid-clean.

1. Clean the file system (FTP/SSH). The SQL injection let attackers write PHP straight to disk (via MySQL's INTO OUTFILE), so hunt for:

  • Suspicious PHP files in /wp-content/cache/ with random alphanumeric names (reported examples look like e042u9xy9ra1.php).
  • A fake backdoor disguised as a "security patch" in /wp-content/mu-plugins/ — must-use plugins load automatically and don't appear in the normal Plugins list, which makes it a favourite hiding spot. Delete anything you didn't put there.
  • Any unknown plugin added under /wp-content/plugins/.

Then update core to 6.9.5 / 7.0.2 to seal the hole, and lock down file editing in wp-config.php:

define( 'DISALLOW_FILE_EDIT', true );
define( 'DISALLOW_FILE_MODS', true );
Enter fullscreen mode Exit fullscreen mode

2. Reset every credential and kill every session. Assume the attacker already has your password hashes.

  • Reset passwords for all users (administrators first), and change the MySQL database password — then update it in wp-config.php.
  • Regenerate your WordPress secret keys and paste them over the old salts in wp-config.php. This instantly invalidates every logged-in session, including the attacker's.
  • Check Users → All Users for any administrator you didn't create, and delete it.

3. Clean the database. The attack seeds spoofed records, often stamped with a fixed date of 2020-01-01 00:00:00 and a payload pointing to example.invalid. Back up first, change the wp_ prefix if yours differs, then:

DELETE FROM wp_posts    WHERE post_type = 'customize_changeset' AND post_date = '2020-01-01 00:00:00';
DELETE FROM wp_posts    WHERE post_type = 'nav_menu_item'        AND post_date = '2020-01-01 00:00:00';
DELETE FROM wp_postmeta WHERE meta_value LIKE '%example.invalid%';
Enter fullscreen mode Exit fullscreen mode

4. Harden so it can't recur. WordPress never needs MySQL's FILE privilege — and that privilege is exactly what let the SQL injection write a webshell to disk in the first place. Revoke it, logged in as the database root user:

REVOKE FILE ON *.* FROM 'your_wp_db_user'@'localhost';FLUSH PRIVILEGES;
Enter fullscreen mode Exit fullscreen mode

One honest caveat: a determined attacker can also bury a shell inside a legitimate-looking theme or plugin file, so if any of the above turns up a real infection, treat the whole install as suspect and diff every core, theme, and plugin file against a known-good copy. And if your site handles customer data or payments, you may have breach-notification obligations too.

A word on those free "wp2shell checkers." Most of them only tell you whether you're patched — they ping the Batch API route and report back. They do not tell you whether you were breached before you patched. Since this was exploited in the wild for days before many sites updated, "patched but already compromised" is the dangerous middle ground, and it's exactly what our free scanner and a manual review are built to catch.

If you'd rather not do that at 2 AM yourself, that's exactly what I do. I offer fixed-price malware removal and cleanup starting at $249 — emergency cleanup, full recovery, and hardening so you're not back here next month. And if you want to understand the real stakes, I've written before about the true cost of a hacked WordPress site — it's rarely the cleanup fee that hurts.

Frequently Asked Questions

Do I need a vulnerable plugin for WP2Shell to work?
No. That's what makes it dangerous. It exploits WordPress core, so a completely stock install with zero third-party plugins is still vulnerable on the affected versions.

I have Wordfence / a security plugin. Am I safe?
A WAF can help block the exploit traffic, but it's not a substitute for patching, and it won't clean a site that was already breached. Update core first, then verify you're not compromised.

WordPress said it auto-updated me. Am I done?
Check the version number yourself — forced auto-updates can fail silently on locked-down sites. If it reads 6.9.5 / 7.0.2 or higher, you're patched against the exploit. You still need to confirm you weren't hit beforehand.

My site is on managed WordPress hosting. Do I still need to worry?
Most reputable managed hosts patched at the platform level within hours, but confirm with your host and still check for compromise if you were on an affected version between July 17 and whenever they patched.

Key Takeaways

WP2Shell is the rare WordPress vulnerability that deserves the panic: unauthenticated, code execution, in core, exploited at scale. Do three things today — confirm your version, update to 6.9.5 or 7.0.2, and check whether you were already breached. Patching closes the door; it doesn't evict anyone already inside.

If the scanner turns up something, or you just want a professional set of eyes before your customers notice, get in touch — I clean these for a living, and moving fast is the whole game.

Originally published on xuro.net.

Top comments (0)