Retour au blog
CVE-2026-60137CVE-2026-63030WordPressWordPress CoreCISA KEVSQL injectionREST APIRCECVE

WordPress Core CVE-2026-60137 + 63030: Chained SQLi to Unauthenticated RCE

Two WordPress core CVEs (6.9.x < 6.9.5, 7.0.x < 7.0.2) chain into unauthenticated RCE on default installations: REST API batch route confusion + author__not_in SQL injection. In CISA KEV.

22 juillet 20268 min de lecture

The vast majority of WordPress compromises come through a third-party plugin or theme. Not this one. On July 21, 2026, CISA added two WordPress core vulnerabilities to the KEV catalog which, chained together, enable unauthenticated remote code execution on a default installation — no plugin, no particular theme, no account.

On a CMS powering roughly 43% of the web, that puts this among the most serious incidents in its history.

The patched versions are 6.9.5 and 7.0.2. If you're not on one of them, stop reading and go update.


The Two CVEs

CVENatureCVSSKEV addedCISA deadline
CVE-2026-63030Interpretation conflict (REST API route confusion)9.8 CRITICAL2026-07-212026-07-24
CVE-2026-60137SQL injection (author__not_in in WP_Query)not published by NVD2026-07-212026-08-04

CVE-2026-63030 has complete NVD data. For CVE-2026-60137, NVD hasn't published a score or vector at the time of writing — but the CVE-2026-63030 description names the exact parameter involved, which is enough to understand the chain.


Technical Details

CVE-2026-60137 — The SQL injection alone is conditional

CISA description:

WordPress Core contains a SQL injection vulnerability when a plugin or theme passes untrusted input to the parameter. This vulnerability can be chained with CVE-2026-63030 to allow an unauthenticated attacker to gain remote code execution on default WordPress installations.

The parameter in question, identified in the CVE-2026-63030 description, is WP_Query's author__not_in — the argument used to exclude content by specific authors from a query.

Taken alone, this CVE has limited reach: a plugin or theme must pass untrusted input into author__not_in. That's a real scenario but not a universal one. Many teams would legitimately have concluded "we're probably not affected."

CVE-2026-63030 — The route confusion that makes the SQLi universal

NVD description:

WordPress 6.9.x before 6.9.5 and 7.0.x before 7.0.2 is affected by a REST API batch endpoint route confusion issue which, combined with the author__not_in WP_Query SQL Injection (CVE-2026-60137), could allow an attacker to perform SQL Injection and achieve Remote Code Execution.

Vector: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H — network, low complexity, no authentication, no user interaction, maximum impact. CWE-436 (Interpretation Conflict).

Since version 5.6, WordPress exposes a batch processing endpoint, /wp-json/batch/v1, allowing multiple REST requests to be submitted in a single HTTP call. "Route confusion" on that endpoint means route resolution through the batch mechanism doesn't produce the same result as the same request sent directly.

In practice, the consequence is that the batch path can reach an internal handler and pass it parameters that, through the normal path, would have been filtered, validated, or refused for lack of authentication. The author__not_in SQLi then becomes reachable without any plugin or theme needing to cooperate — which the description summarises as "on default WordPress installations."

That's what makes this severe: CVE-2026-63030 turns a conditional SQLi into a universal one.

From SQL injection to RCE

The KEV catalog asserts the outcome is code execution. The classic paths from SQLi to RCE on WordPress are well documented:

  • Injection into the wp_options table — many options are stored serialised and unserialised on read. Writing a forged PHP object into an option opens the door to PHP object injection, exploitable with a gadget chain present in core or a dependency
  • Administrator account creation via INSERT into wp_users and wp_usermeta, then uploading a malicious plugin from the admin interface
  • File write via INTO OUTFILE if the MySQL account holds the FILE privilege

I don't know which of these the real exploit uses — neither WordPress nor CISA detailed it. It changes nothing about what you should do.


Affected Products and Versions

WordPress branchAffected versionsPatched version
6.9.x< 6.9.56.9.5
7.0.x< 7.0.27.0.2

Check your version:

# WP-CLI
wp core version

# Or in admin: Dashboard → Updates

Earlier branches (6.8 and before) aren't named in the advisory. If you're on an unmaintained branch, you have a broader problem than these two CVEs: move to a supported version.


Exploitation and Impact

Why you should assume mass exploitation

This chain has every ingredient for industrialised exploitation:

  • No authentication, no user interaction — a single POST suffices
  • Trivially fingerprintable target — the WordPress version is often exposed in <meta name="generator">, in asset ?ver= parameters, or inferable from static file hashes
  • Default installation is enough — no need to guess which plugin is installed
  • Enormous target population — every un-updated WordPress site is exploitable identically

CISA's three-day deadline (July 24 for CVE-2026-63030) indicates observed exploitation. At WordPress scale, that means mass automated scanning.

After compromise

  • SEO spam injection and conditional redirects (a visitor from Google gets redirected, the administrator sees a normal site)
  • Persistent webshell in theme or upload directories
  • Database exfiltration: user accounts, password hashes, customer data, and for e-commerce sites, order history
  • Dormant administrator accounts created for later return
  • Pivot on shared hosting to other sites under the same account

A reminder that applies to everyone here: a WordPress compromise durably damages search rankings. Google detects the injection, demotes the site, and sometimes flags it as dangerous in results. The SEO damage long outlives the technical cleanup.


Detection and IOCs

Web server logs — the batch endpoint

This is the primary control point. In normal use, /wp-json/batch/v1 sees very little traffic: it mainly serves the Gutenberg block editor and a few integrations. Any significant volume of requests to it is abnormal.

# Apache / Nginx — requests to the batch endpoint
grep -E "POST .*/wp-json/batch/v1" /var/log/nginx/access.log | tail -100

# Cross-referenced with SQL injection patterns
grep -E "wp-json/batch/v1" /var/log/nginx/access.log | \
  grep -iE "union|select|sleep\(|benchmark\(|author__not_in"

MySQL logs

If you can enable query logging (even temporarily), look for injection signatures on queries from the WordPress account:

-- MySQL: enable query logging
SET GLOBAL log_output = 'TABLE';
SET GLOBAL general_log = 'ON';

Patterns to hunt: UNION SELECT against wp_users, INSERT into wp_users / wp_usermeta, UPDATE on wp_options outside legitimate operations.

Administrator accounts

The fastest and most revealing check:

wp user list --role=administrator --fields=ID,user_login,user_email,user_registered

Any unrecognised account — especially registered after July 17 — should be treated as confirmed compromise.

Files

# Recent PHP files in uploads (should never return anything)
find wp-content/uploads -name "*.php" -o -name "*.phtml" -o -name "*.phar" 2>/dev/null

# Modified core files
wp core verify-checksums

wp core verify-checksums compares your core files against official checksums. It's an excellent detector for backdoors injected into core, and it's instant.

Serialised option integrity

SELECT option_name, LEFT(option_value, 120) AS excerpt
FROM wp_options
WHERE option_value LIKE 'O:%' OR option_value LIKE 'a:%:{%O:%';

A serialised PHP object (O:) in an option that never held one is a strong signal of an object injection attempt.


Mitigation and Patch

1. Update — immediately

wp core update --version=6.9.5
# or
wp core update --version=7.0.2

Then verify:

wp core version && wp core verify-checksums

If you manage a fleet of sites, WP-CLI in a loop is the fastest route. Core auto-updates, if enabled, have normally already applied the fix — verify rather than assume, they fail silently more often than people think (file permissions, stuck maintenance mode, WP_AUTO_UPDATE_CORE disabled).

2. If you can't patch right away

Block the batch endpoint at the web server level. It's a targeted mitigation that breaks little (the Gutenberg editor may lose some optimisations):

location = /wp-json/batch/v1 {
    deny all;
    return 403;
}
<Location "/wp-json/batch/v1">
    Require all denied
</Location>

This is a holding measure, not a fix: the author__not_in SQLi remains present and exploitable if a plugin feeds it untrusted input.

3. After patching — treat compromise as a live hypothesis

The CVEs were published July 17 and KEV-listed July 21. If you updated after July 20, run a hunt:

  1. wp core verify-checksums — core integrity
  2. List administrators and accounts created since July 15
  3. Search for .php in wp-content/uploads
  4. Review unexpected serialised wp_options
  5. Check scheduled tasks: wp cron event list
  6. Rotate administrator passwords and database credentials
  7. Google Search Console → Security Issues, then request a review after cleanup

4. Long-term hardening

  • Forbid PHP execution in wp-content/uploads — neutralises an entire attack class, independent of these CVEs
  • DISALLOW_FILE_EDIT in wp-config.php to disable the admin file editor
  • Minimal MySQL privileges: the WordPress account needs neither FILE, GRANT, nor SUPER
  • Core auto-updates enabled and monitored — with an alert when they fail

Why Continuous Monitoring Matters, Even for CMS Cores

This episode breaks a comfortable intuition: "WordPress CVEs are always some obscure plugin, we're fine." Here, the default installation is enough, and the chain combines a flaw judged conditional with another that removes the condition. It's also a reminder that an isolated CVE's score says nothing about its chainability — CVE-2026-60137 alone looked like a plugin problem; it became the link in a universal RCE.

With cveo.tech, inventory your WordPress sites with their exact core and extension versions, and get automatic alerts whenever a critical CVE — especially a CISA KEV addition — affects them. Across a population of sites where scanning bots arrive within hours, knowing the same day which installations are exposed is the difference between an update and an incident response.

Surveillez les CVE avec l'IA

Recherche IA, scoring CVSS, surveillance de parc et alertes automatiques.