gichirimaku / wp2shell-PoC
git clone https://github.com/gichirimaku/wp2shell-PoC.git
CVE-2026-63030 + CVE-2026-60137 exploit RCE chain.
—
stars, 24h
+562
stars, 7 days · #109
+562
stars, 30 days · #509
562
★ total · +562% this week
53
forks · 0 open issues
Star history starts 2026-10-20; the chart appears after the second daily snapshot.
LanguagePython
License—
Created2026-10-15 (5d ago)
Last pushtoday
Watchers6
OwnerUser
GitHub topics
Links
README excerpt
# wp2shell-PoC > **⚠ This tool is created solely for educational or bug bounty purpose only. Unauthorized use outside of controlled environments is strictly prohibited.** ## Overview Proof-of-concept for the wp2shell vulnerability chain affecting WordPress Core, combining CVE-2026-63030 and CVE-2026-60137. The project demonstrates the interaction between the REST API Batch route confusion vulnerability and a WP_Query SQL injection, resulting in an unauthenticated path to full WordPress compromise and remote code execution (RCE). **Read the full advisory here** # How it works **wp2shell** is a pre-authentication RCE chain in WordPress core, combining CVE-2026-63030 (route confusion in the batch REST endpoint) and CVE-2026-60137 (SQL injection in WP_Query). **The route confusion:** `/wp-json/batch/v1` processes multiple sub-requests via parallel `$matches` and `$validation` arrays indexed by position. A sub-request with a malformed path (e.g., `http://:`) is appended to `$validation` but not `$matches` due to a `continue` statement, desynchronizing the arrays. Later requests are dispatched under the handler meant for the *next* request, bypassing schema validation and permission checks. **The SQL injection:** Two nested batch calls exploit this. The outer batch bypasses the method allow-list (normally blocking GET). The inner batch delivers a scalar `author_exclude` string to `GET /wp/v2/posts` - the desync routes it past validation, and `WP_Query` interpolates the unsanitized string directly into SQL, yielding a UNION-based blind injection. **Cache poisoning:** The SQLi returns forged `WP_Post` objects, which WordPress caches in-memory. These fake posts contain `[embed]` shortcodes that cause WordPress to create real `oembed_cache` database rows from the fake references. **Changeset escalation:** Using the SQLi, the attacker forges a `customize_changeset` post in-memory with `"user_id": 1` in its JSON. A cycle-detection gadget triggers `wp_update_post()` without overwriting `post_content`, preserving the attacker's payload. Applying the changeset temporarily assumes the administrator's identity. **Hook re-entry:** A fabricated post with status `parse` and type `request` fires the `parse_request` hook, replaying the entire batch request with the assumed admin role. This time, a `POST /wp/v2/users` sub-request succeeds, creating a new admin account. **Code execution:** The attacker logs in as the created admin and uploads a malicious plugin to run arbitrary commands. # Affected versions | Version| Status | |---------------|--------| | WordPress 6.9.0 – 6.9.4 | Vulnerable | | WordPress 7.0.0 – 7.0.1 | Vulnerable | | WordPress 6.9.5 | Fixed | | WordPress 7.0.2+ | Fixed | # Usage **To use this PoC, the only requirement is Python 3.8+.** Run it from the repository directory to perform a vulnerability check: [code] ### Check Mode (default) Performs a single vulnerability check. Sends a benign batch marker probe that detects the route confusion bug with