
Non-intrusive detection scanner for the WordPress wp2shell pre-auth RCE chain (CVE-2026-63030 + CVE-2026-60137). Detection-only, no exploitation.
Non-intrusive detection scanner for recent WordPress core vulnerabilities — including the wp2shell pre-authentication RCE chain.
wp2shell_scanner.py fingerprints a WordPress site's core version and reads its
publicly advertised REST API surface, then classifies each tracked core CVE
independently against the detected version. Verdicts are branch-aware — e.g. a
6.8.x site is correctly reported as exposed to the SQL-injection CVE but not to the
full RCE chain. It detects only: no exploit payload is ever sent. Single file, one
dependency (requests), CI-friendly exit codes, and client-ready HTML / JSON / e-mail
reports.
⚠️ Authorised use only. Scan systems you own or are explicitly authorised (in writing) to test. The scanner sends an identifying
User-Agentso blue teams can attribute the traffic — it does not hide.
The wp2shell RCE chain = CVE-2026-63030 + CVE-2026-60137 together → pre-auth
remote code execution on a default install. The scanner reports the chain as exposed
only when both CVEs classify as vulnerable for the detected version.
Branch nuances the scanner gets right:
6.8.x carries the SQL injection (CVE-2026-60137) only — not the RCE chain.6.9 branch, CVE-2026-3906 (Notes) is fixed in 6.9.2, but the wp2shell
chain is not closed until 6.9.5. So 6.9.2/6.9.4 read patched for the Notes
bug yet remain vulnerable to the RCE chain — the scanner therefore only recommends
6.9.5 or later on that branch, never 6.9.4.Operationally important: technical write-ups and a working PoC for wp2shell are already public. Version detection is now the absolute minimum — the priority is patching. Updating closes the vulnerable path but does not remove a backdoor planted before the patch — hence the compromise-assessment step in the report.
This is a core-version scanner. Plugin and theme CVEs — the large majority of the WPScan / Patchstack catalogue — require a live, curated feed and per-plugin version enumeration, and are intentionally out of scope here. Within its lane (recent WordPress core CVEs), it aims to be precise and branch-accurate rather than to duplicate a commercial vulnerability database.
<meta name="generator"> on the homepage/readme.html<generator> tag/wp-links-opml.php (OPML)/wp-json/ to see whether WordPress
advertises the batch/v1 namespace in its REST index. This confirms the
namespace is registered, not that the endpoint is reachable through a WAF.
No batch request and no payload are sent.It does not exploit anything. No SQL-injection payload, no batch-route-confusion request, no attempt to execute code or read data. Detection is version-based plus a passive read of the publicly advertised API surface.
pip install requests
# single target
python3 wp2shell_scanner.py -t https://site.example --authorized
# list of targets (one per line, # comments allowed)
python3 wp2shell_scanner.py -T scope.txt --authorized -o ./reports
# preview the output formats with synthetic data — no network, no auth needed
python3 wp2shell_scanner.py --demo -o ./reports
The --authorized flag is an explicit authorisation gate — live scans refuse to run
without it.
| Code | Meaning |
|---|---|
2 | At least one target vulnerable |
1 | At least one target inconclusive / error |
0 | Clean (patched / not affected / not WordPress) |
The notification e-mail recipient is the CSSLTD_CONTACT constant near the top of the
script (default [email protected]). Edit it to your own intake address.
The examples/ directory contains synthetic (--demo) output for a
fictional vulnerable host (example.com, WordPress 6.9.1 — exposed to all three tracked CVEs):
wp2shell_report_example.com.html — the client-ready HTML reportwp2shell_example.com.json — the JSON recordwp2shell_email_example.com.txt — the draft notification e-mailThese are generated from fabricated data to illustrate the report format. They are not the result of scanning any real site.
6.9.5+ is clear — 6.9.4 still has the wp2shell chain.)uploads/, wp-config.php, wp-cron, and admin
accounts; run file-integrity checks against known-good core./wp-json/batch/v1).This tool is for authorised security testing only. You are responsible for ensuring you have permission to scan any target. Unauthorised scanning may be unlawful. The authors accept no liability for misuse.
| CVE | Weakness | Access | Affected core | Fixed in |
|---|
| CVE-2026-63030 — wp2shell | CWE-436 — REST batch route confusion → RCE (Critical; CVSS 9.8 WPScan CNA / 7.5 CISA-ADP; GHSA-ff9f-jf42-662q) | Unauthenticated | 6.9.0–6.9.4, 7.0.0–7.0.1 | 6.9.5, 7.0.2 |
| CVE-2026-60137 | CWE-89 — SQL injection in WP_Query author__not_in (Moderate standalone, CVSS 5.9; Critical in-chain; GHSA-fpp7-x2x2-2mjf) | Unauthenticated | 6.8.0–6.8.5, 6.9.0–6.9.4, 7.0.0–7.0.1 | 6.8.6, 6.9.5, 7.0.2 |
| CVE-2026-3906 | CWE-862 — Notes REST API missing authorization (Moderate, CVSS 4.3, GHSA-6x83-fcf5-r65g) | Subscriber+ | 6.9.0–6.9.1 | 6.9.2 |
| Flag | Meaning |
|---|
-t, --target | Single target URL or host |
-T, --targets-file | File with one target per line |
--demo | Generate a SAMPLE report/e-mail from synthetic data (no network) |
-o, --output-dir | Output directory (default ./wp2shell_reports) |
--formats | Comma list: json,html,email (default: all) |
--authorized | Authorisation gate — required for live scans |
--timeout | HTTP timeout in seconds (default 12) |
--delay | Seconds between targets (be polite; default 1.0) |
--insecure | Do not verify TLS certificates |
--quiet | Suppress the console summary |
| Verdict | Meaning |
|---|
VULNERABLE | Detected version falls inside an affected range — patch immediately |
PATCHED | On a fixed release; not exposed to the tracked CVEs |
NOT_AFFECTED | Version predates the earliest tracked flaw (< 6.8.0 — CVE-2026-60137) |
UNKNOWN | Version could not be confirmed, vectors disagreed, or a pre-release build was seen — verify manually |
NOT_WORDPRESS | No WordPress fingerprint found |