Protocolo Flight de React: Sumideros de Deserialización y Ataques RCE

Descubre cómo los sumideros de deserialización del protocolo Flight de React permitieron CVE-2025-55182 (React2Shell) RCE. Aprende defensas: validación, CSRF,

domingo, 26 de julio de 2026 • 7 min de lectura • Equipo Q2BSTUDIO

Sumideros de deserialización en RSC: Riesgos y defensas

El ecosistema de React ha experimentado una transformación profunda con la llegada de los Server Components y el protocolo Flight. Este sistema de comunicación en tiempo real entre servidor y cliente promete eficiencia y rendimiento, pero también ha abierto una puerta a vulnerabilidades críticas que ningún equipo de desarrollo debería ignorar. En este artículo analizamos cómo Flight convierte datos estructurados en vectores de ataque, los incidentes más graves documentados y las medidas que pueden tomar las organizaciones para proteger sus aplicaciones.

El protocolo Flight no es un simple formato JSON. Se trata de un sistema de streaming que transporta referencias a módulos, acciones del servidor, promesas asíncronas y elementos de interfaz. Cada línea del flujo contiene una instrucción que el runtime de React interpreta para reconstruir el árbol de componentes en el cliente. Eso significa que el servidor envía no solo datos, sino comportamiento ejecutable. Y cuando un atacante logra manipular ese flujo, las consecuencias pueden ser catastróficas.

Para entender el riesgo, hay que observar el sistema de prefijos $. Cuando el parser encuentra una cadena que comienza con $, la interpreta como una referencia a otro fragmento del flujo. Por ejemplo, $2 apunta al fragmento 2, mientras que $1:user:name indica que debe acceder a la propiedad user.name del fragmento 1. Este recorrido de propiedades, conocido como $:, permite navegar por cualquier objeto, incluidos los prototipos. En los sistemas JavaScript, el acceso a __proto__ o constructor puede conducir a la modificación de prototipos compartidos, abriendo la puerta a ataques de contaminación de prototipos (prototype pollution).

La vulnerabilidad más sonada fue CVE-2025-55182, apodada React2Shell, que alcanzó una puntuación CVSS de 10.0. Un atacante sin autenticación podía enviar una única petición HTTP a un endpoint de Server Function y obtener acceso completo al shell del servidor. El mecanismo combinaba varias características del protocolo: el recorrido de prototipos para llegar al constructor Function, la autorreferencia a fragmentos internos con $@, el secuestro de promesas (Thenable hijack) y el desencadenamiento a través del manejador de blobs $B. Todo ello demostraba que Flight no solo serializa datos, sino que reconstruye comportamiento de forma peligrosa.

Tras la publicación del parche, el equipo de React corrigió el problema añadiendo una verificación de hasOwnProperty en cada acceso a propiedades. Sin embargo, la estructura fundamental del protocolo sigue siendo la misma: el recorrido de propiedades mediante $: permanece intacto, solo que ahora se validan los pasos. Para muchos expertos en ciberseguridad, esto representa un parche sintomático y no un rediseño estructural. El riesgo latente es que futuras vulnerabilidades puedan surgir del mismo patrón.

Además del RCE, se documentaron otras vulnerabilidades en el mismo ecosistema. CVE-2025-55183 permitía la exposición de código fuente cuando una Server Action serializaba un argumento malicioso. CVE-2025-55184 y CVE-2025-67779 eran denegaciones de servicio por recursión infinita de promesas. CVE-2026-23864 explotaba el buffering ilimitado del cuerpo de la petición para agotar la memoria. Finalmente, CVE-2026-27978 era un bypass de CSRF que ocurría cuando el navegador enviaba Origin: null desde un iframe sandboxeado, y Next.js lo trataba como un origen ausente en lugar de cruzado.

Ante este panorama, las empresas que desarrollan aplicaciones con React Server Components deben adoptar defensas en profundidad. La primera y más efectiva es la validación de entrada en cada Server Action. Utilizar librerías como Zod o Valibot para definir esquemas estrictos y ejecutar safeParse antes de cualquier lógica de negocio impide que datos malformados lleguen al motor de deserialización. Es crucial no desestructurar los argumentos antes de validarlos, porque eso ya implica acceder a propiedades sobre datos no confiables.

El paquete server-only es otra barrera sencilla pero poderosa. Al importarlo en archivos que contengan credenciales, consultas a bases de datos o lógica interna, se garantiza que ningún componente cliente pueda importarlos directa o transitivamente. Sin embargo, hay que tener cuidado con los archivos barrel que reexportan funciones; si un barrel mezcla código de servidor y cliente, la protección se diluye.

La protección contra CSRF requiere ir más allá de los valores por defecto del framework. Configurar las cookies con SameSite=Strict, generar tokens CSRF explícitos para operaciones sensibles y evitar a toda costa añadir 'null' a la lista de orígenes permitidos son prácticas imprescindibles. El error de Next.js que permitió el bypass con Origin: null se corrigió en la versión 16.1.7, pero muchas aplicaciones aún ejecutan versiones anteriores.

La API de Taint de React, con funciones como taintObjectReference y taintUniqueValue, ofrece una capa de seguridad en tiempo de desarrollo. Permite marcar objetos o cadenas para que el serializador lance un error si intentan cruzar al cliente. No obstante, su efectividad es limitada: solo funciona con referencias al mismo objeto, no con copias, desestructuraciones o transformaciones. Es un guardarraíl útil, pero no un cortafuegos.

Los WAF (Web Application Firewalls) pueden añadir una detección superficial de patrones conocidos, como cadenas constructor:constructor o __proto__. Sin embargo, los atacantes sofisticados rellenan el payload con datos basura antes de la parte maliciosa para eludir la inspección, o usan codificación chunked. Confiar únicamente en un WAF es peligroso; debe combinarse con las defensas anteriores.

Más allá de los parches, hay riesgos estructurales que persisten. El ataque de intermediario (MITM) sobre el flujo Flight es viable si un atacante controla la red (CDN comprometido, caché envenenada). Puede modificar filas $I para redirigir la carga de módulos, inyectar referencias $F para activar RPC ocultos o alterar props que lleven a XSS si el componente usa dangerouslySetInnerHTML. El escape de prefijos $ que aplica el serializador solo protege contra datos de usuario, no contra un atacante que escribe directamente en el flujo.

La enumeración de Server Actions es otro vector. El archivo server-reference-manifest.json contiene el mapa de todas las acciones con sus IDs hash. Si ese manifiesto queda expuesto por una mala configuración del hosting o un path traversal, el atacante obtiene un catálogo completo de endpoints RPC y puede realizar ataques de IDOR o manipulación de parámetros.

La manipulación de cierres encriptados (encrypted closures) también es preocupante. Cuando una Server Action captura variables de su ámbito, Next.js las encripta con una clave AES. Si el atacante obtiene acceso de lectura a archivos (por SSRF o path traversal), puede extraer la clave, descifrar, modificar y volver a encriptar el estado, haciendo que el servidor acepte datos falsificados.

Finalmente, existe la posibilidad de activación de módulos inertes mediante IDs de módulo. Si un paquete comprometido está presente en node_modules como dependencia transitiva pero nunca se importa directamente, el bundler lo incluye en un chunk pero no se carga. Un atacante que pueda inyectar una fila $I en el flujo Flight podría forzar la carga de ese chunk, activando código que de otro modo permanecería dormido.

Este tipo de vulnerabilidades no son nuevas. Google Web Toolkit, Java Server Faces y ASP.NET ya sufrieron problemas similares con sus formatos de serialización personalizados. La lección es siempre la misma: cuando un framework inventa un protocolo de comunicación que transporta comportamiento ejecutable, la superficie de ataque se expande más allá de lo que los desarrolladores suelen anticipar. La confianza ciega en que el servidor es el único productor de esos datos es insostenible.

Para las empresas que construyen aplicaciones a medida con tecnologías modernas, la ciberseguridad debe ser parte integral del proceso de desarrollo. No basta con aplicar parches; hay que diseñar arquitecturas que limiten el impacto de cualquier vulnerabilidad futura. En Q2BSTUDIO, acompañamos a nuestros clientes en todo el ciclo de vida del software, desde el análisis de riesgos hasta la implementación de defensas en profundidad, incluyendo integración con servicios cloud AWS/Azure, sistemas de inteligencia artificial y Business Intelligence con Power BI. Además, desarrollamos agentes de IA que automatizan tareas de monitoreo y respuesta ante incidentes, reduciendo la ventana de exposición.

La comunidad de seguridad ha demostrado que el protocolo Flight, por su propia naturaleza, seguirá siendo un objetivo atractivo. Mientras no se implementen mecanismos de validación criptográfica de los flujos serializados, firmas de árboles de componentes o controles de integridad de contenido, las aplicaciones basadas en Server Components dependerán de la vigilancia constante de sus equipos de desarrollo y de la colaboración con expertos en seguridad. La inversión en prevención y en formación de equipos es la única garantía frente a amenazas que evolucionan tan rápido como la tecnología que intentamos proteger.

¿UNA PAUSA?

Juega un momento antes de irte

NUESTROS SERVICIOS

Cómo podemos ayudarte

¿Tienes un proyecto en mente?

Cuéntanos tu visión y la convertimos en una solución de software. Sea cual sea el alcance, hacemos realidad tu idea.