Blog

DygDog Adds Passive Detection for WordPress wp2shell Exposure (CVE-2026-63030)

DygDog Team··7 min read


WordPress powers a substantial share of the public web. When a pre-authentication remote code execution chain surfaces in its core, the window between disclosure and active exploitation is short. If your installation is on WordPress 6.9.0–6.9.4 or 7.0.0–7.0.1, update to 6.9.5 or 7.0.2 now — before reading further.

DygDog's free WordPress security scanner now includes Module 73: WordPress wp2shell RCE Exposure, a passive assessment that determines whether a publicly reachable WordPress installation appears to be in the affected version range and, separately, whether the relevant REST API endpoint is publicly reachable. It runs automatically on every DygDog scan at no cost.

This post explains what the vulnerability chain is, exactly what DygDog checks and how it reports results, and what remediation looks like.

What is the wp2shell chain?

The wp2shell chain combines two CVEs that, when present together in an unpatched WordPress installation, may permit unauthenticated remote code execution.

CVE-2026-63030 is a REST API batch-route confusion and interpretation-conflict issue (CWE-436). The WordPress REST API's batch endpoint at /wp-json/batch/v1 processes multiple API requests in a single call. A flaw in how that endpoint resolves routing context allows a carefully structured request to be interpreted in an unintended way by the routing layer.

CVE-2026-60137 is a SQL injection in the WP_Query author__not_in parameter (CWE-89). Under normal conditions, WordPress sanitises query arguments before constructing SQL. This issue allows unsanitised input to reach the database layer via a specific query path.

When both vulnerabilities are present and the batch endpoint is reachable, an unauthenticated attacker may be able to chain them to execute arbitrary code on the server. No authentication, no plugin, and no administrator action is required.

Neither CVE involves a WordPress plugin or theme. Both affect WordPress core directly.

Who is affected?

The wp2shell chain affects WordPress core. The affected and patched versions are:

BranchAffectedPatched
6.96.9.0 – 6.9.46.9.5
7.07.0.0 – 7.0.17.0.2

Versions prior to 6.9.0 and versions 6.9.5, 7.0.2, and later are outside this affected range. DygDog's version comparison is conservative: if a version string cannot be parsed to an exact X.Y.Z, the module does not report a vulnerability finding.

What DygDog Module 73 checks

Module 73 performs three sequential passive checks — all safe, read-only probes against publicly observable signals:

Check 1 — WordPress presence. A GET request is made to the homepage. If the response HTML contains wp-content/, wp-includes/, or a content="WordPress" meta attribute, the site is fingerprinted as WordPress. Additionally, a GET to /wp-json/ is made; a JSON response containing namespaces, name, or url fields also confirms WordPress. If neither signal is present, the remaining checks are skipped and the result is a pass.

Check 2 — Version extraction. DygDog extracts the WordPress version from passive signals in priority order:

  1. <meta name="generator" content="WordPress X.Y.Z"> — highest confidence
  2. ?ver=X.Y.Z query strings on /wp-includes/ asset URLs (most-frequent value wins across all occurrences)
  3. generator or version fields in the /wp-json/ root response

The module does not fetch readme.html. That file is handled separately by the framework fingerprinting module, and its absence or presence does not affect the wp2shell assessment. A site that suppresses all version signals receives an informational result, not a vulnerability finding.

Check 3 — Batch endpoint reachability. Only if the version is in an affected range does the module probe /wp-json/batch/v1 — using a HEAD request (no body, no parameters), with a GET fallback only if HEAD returns HTTP 405. A 2xx response is recorded as reachable. 401 or 403 is recorded as access-controlled. 404 or 501 is recorded as unavailable.

The module never sends a POST, PUT, PATCH, or DELETE request. It never attaches a request body. It never sends SQL syntax, exploit strings, authentication credentials, or any mutation.

How DygDog reports results

ResultSeverityCondition
Critical FAILCriticalAffected version detected AND /wp-json/batch/v1 returns 2xx
Critical WARNCriticalAffected version detected AND batch endpoint reachability not confirmed (blocked, unavailable, or indeterminate)
INFO / UNKNOWNInfoWordPress detected AND version not available from any passive source
PASSPatched version detected, version outside affected ranges, or site is not WordPress

Important limitation. Both Critical results include the following explicit disclaimer: "This is a version-and-exposure assessment only — DygDog does not send exploit payloads and cannot confirm whether the target is actively exploitable." A Critical FAIL means DygDog observed an affected version and a publicly reachable batch endpoint. It does not mean the site has been compromised, or that exploitation would succeed. A WARN result means the version is affected regardless of endpoint availability — patching is required.

Assessment confidence values are embedded in the finding evidence: 0.95 for FAIL, 0.80 for WARN, 0.70 for UNKNOWN.

How to remediate

  1. Update WordPress immediately to 6.9.5 (if on the 6.9 branch) or 7.0.2 (if on the 7.0 branch). In the WordPress admin, navigate to Dashboard → Updates. Via WP-CLI: wp core update.
  2. Verify the update completed and that no unsupported or orphaned core files remain.
  3. As a temporary defence-in-depth measure only, restrict anonymous access to /wp-json/batch/v1 at your WAF or reverse-proxy layer. This is not a substitute for patching — a WAF restriction only addresses the batch endpoint reachability component of the chain; the underlying SQL injection (CVE-2026-60137) remains present in unpatched installations.
  4. Review REST API, web server, and authentication logs for any unusual activity against the batch endpoint prior to patching.

Why passive scanning matters here

DygDog is an external, passive scanner. Module 73 makes no authenticated requests to your application, executes no plugin or theme code, sends no login attempts, and touches no internal endpoints. Every probe uses safe read-only HTTP methods (GET and HEAD) against publicly observable signals — the same information any external party can already see.

This passive approach means the scan is safe to run against a production WordPress site without any risk of disrupting your application or triggering false-positive incident alerts. It also means DygDog can assess sites you do not control, as part of your external attack surface monitoring.

You can run a passive WordPress security assessment — covering wp2shell exposure and 72 other checks — at dyg.dog/wordpress.

Frequently asked questions

Is DygDog safe to run against a production WordPress site?

Yes. DygDog makes only safe, read-only GET and HEAD requests against publicly accessible endpoints. It sends no payloads, no credentials, no POST requests, and no mutation of any kind. It is designed to be safe to run against live production sites.

Does a Critical result mean my site was exploited?

No. A Critical finding from Module 73 means DygDog observed an affected WordPress version and, in the case of FAIL, a publicly reachable batch endpoint. DygDog does not send exploit payloads and cannot determine whether exploitation has occurred or would succeed. A Critical result means you should patch immediately and review your logs.

Which WordPress versions need updating?

WordPress 6.9.0 through 6.9.4 should update to 6.9.5. WordPress 7.0.0 and 7.0.1 should update to 7.0.2. Versions prior to 6.9.0 are outside the wp2shell affected range, though keeping WordPress up to date is always recommended.

What does a hidden WordPress version mean?

If your WordPress installation suppresses all version signals — no meta generator tag, no ?ver= parameters on wp-includes assets, and no version in the wp-json root — DygDog cannot determine your patch status remotely. The result is an informational finding (INFO / UNKNOWN classification). Suppressing version signals is a reasonable security measure, but it does not replace patching.

Does blocking the batch endpoint replace patching?

No. Restricting access to /wp-json/batch/v1 addresses one observable component of the chain. The underlying SQL injection vulnerability (CVE-2026-60137) remains present in an unpatched installation. Applying the WordPress security update is the only complete remediation.


Run a passive WordPress security scan