Node2Shell: RCE de Brotli en Node.js, Bun y Python (CVE-2026-111497)
CVE-2026-111497, un desbordamiento del decodificador con CVSS v4.0 9.2, afecta a Node.js, Bun, .NET, los paquetes Brotli de Python, Envoy e Istio; las correcciones se publicaron del 21 al 25 de octubre de 2026.
Resumen
- CVE-2026-111497 es una escritura fuera de límites en el decodificador C de Brotli, el código que descomprime datos Brotli (
Content-Encoding: br) en toda la web. Un flujo manipulado corrompe la memoria del proceso y provoca una caída, divulgación de memoria o ejecución de código. El registro CVE le asigna CVSS v4.0 9.2 (CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N); Node.js lo clasifica como de gravedad alta y Red Hat le asigna 8.1. - El fallo reside en Google Brotli de 1.0.3 a 1.2.0 y se propaga a todo lo que incorpora ese código: Node.js 22.x, 24.x y 26.x, Bun 1.4.3 y anteriores, los paquetes Brotli y brotlicffi de PyPI, Envoy e Istio cuando está habilitada la descompresión Brotli, las compilaciones independientes de cdxgen y el entorno de ejecución .NET, corregido el 25 de octubre desde .NET 8 hasta las versiones candidatas de .NET 11.
- La exposición requiere decodificar datos Brotli controlados por otra parte: una respuesta de
fetch(), un cuerpo de solicitud de Express 5 o body-parser 2, un filtro de descompresión de un proxy o clientes HTTP de Python, que decodifican Brotli automáticamente en cuanto se instala el paquete. - No se conoce explotación en ataques reales: la evaluación de CISA del 23 de octubre registró la explotación como «none». El equipo rojo de Imperva demostró ejecución de código en una compilación ARM64 de Node.js 24.22.0 sin modificar y no ha publicado el exploit; la prueba de concepto pública aparecida el 22 de octubre solo alcanza ejecución de código en una compilación deliberadamente debilitada, y produce una caída y una lectura limitada de memoria en compilaciones estándar. Red Hat afirma que no hay una prueba de concepto pública fiable para ejecutar código.
- Actualice ahora todas las copias del decodificador, reinicie los servicios y reconstruya las imágenes de contenedores: un proceso en ejecución conserva el decodificador antiguo hasta reiniciarse.
¿Estoy afectado?
Está afectado si se cumplen ambas condiciones:
- El software que ejecuta incorpora o enlaza una versión afectada del decodificador Brotli y decodifica datos Brotli de partes que usted no controla por completo. Un servidor HTTP básico de Node.js no decodifica por sí mismo los cuerpos de solicitudes, por lo que la exposición llega mediante las rutas enumeradas a continuación.
- En Python específicamente, el riesgo proviene de tener instalado el paquete Brotli o brotlicffi. En cuanto está presente cualquiera de ellos, clientes HTTP como requests, urllib3, httpx y aiohttp decodifican respuestas Brotli por sí solos, por lo que una aplicación puede estar expuesta sin importar nunca Brotli en su propio código.
| Software | Versiones afectadas | Versión corregida |
|---|---|---|
| Google Brotli (biblioteca C) | 1.0.3 a 1.2.0 | 1.0.10, 1.1.1 o 1.2.1, según la rama (21 de octubre de 2026) |
| Node.js 26.x | Anteriores a 26.12.1 | 26.12.1 (21 de octubre de 2026) |
| Node.js 24.x | Anteriores a 24.22.1 | 24.22.1 (21 de octubre de 2026) |
| Node.js 22.x | Anteriores a 22.23.4 | 22.23.4 (21 de octubre de 2026) |
| Node.js 20.x y anteriores | Todas (fin de vida útil) | Ninguna: migre a una rama con soporte |
| Bun | 1.4.3 y anteriores | 1.4.4 (22 de octubre de 2026) |
| .NET 8 | 8.0.0 a 8.0.32 | 8.0.33 (25 de octubre de 2026) |
| .NET 9 | 9.0.0 a 9.0.21 | 9.0.22 (25 de octubre de 2026) |
| .NET 10 | 10.0.0 a 10.0.13 | 10.0.14 (25 de octubre de 2026) |
| Vistas previas y RC de .NET 11 | 11.0.0-preview.1 a 11.0.0-rc.3.26522.147 | 11.0.0-rc.3.26522.148 |
| Brotli de PyPI | Anteriores a 1.2.1 | 1.2.1 |
| brotlicffi de PyPI | Anteriores a 1.2.1.0 | 1.2.1.0 |
| Go, andybalholm/brotli | Anteriores a 1.2.7 | 1.2.7 (23 de octubre de 2026) |
| Envoy | 1.36.11, 1.37.7, 1.38.5, 1.39.2 | 1.36.12, 1.37.8, 1.38.6, 1.39.3, 1.40.0 |
| Istio | 1.29.0 a 1.29.8, 1.30.0 a 1.30.5, 1.31.0 a 1.31.1 | 1.29.9, 1.30.6, 1.31.2 |
| Binarios e imágenes independientes de cdxgen | 13.4.0 y anteriores, 12.8.8 y anteriores | 13.5.0, 12.8.9 |
| Compilaciones oficiales PHP para Windows | 8.5.12, 8.4.27, 8.3.36 y 8.2.35 del 21 de octubre de 2026 (Brotli 1.2.0 incluido, según sus SBOM) | 8.5.12-1, 8.4.27-1, 8.3.36-1 y 8.2.35-1, las recompilaciones del 26 de octubre con Brotli 1.2.1 |
El aviso .NET, GHSA-p3jp-9v83-76w9 (gravedad alta, CVSS v3.1 8.1), cubre 225 paquetes NuGet de las cuatro ramas y tiene la misma condición previa que los proxies: ASP.NET Core y HttpClient no descomprimen automáticamente datos Brotli en sus configuraciones predeterminadas, de modo que una aplicación .NET solo está expuesta cuando habilita la descompresión Brotli o utiliza explícitamente BrotliStream, BrotliDecoder o las opciones de descompresión automática sobre datos controlados por un atacante. .NET Framework no está afectado.
La adaptación del decodificador a Go, andybalholm/brotli, contenía el mismo retorno ambiguo en decodeBlockTypeAndLength, y Andy Balholm lo corrigió el 23 de octubre de 2026 con el commit 33c2a988, una adaptación directa de la corrección Google 0ed4268, publicada como v1.2.7 sin aviso ni CVE. El alcance es más limitado que el del decodificador C: los accesos a segmentos con comprobación de límites de Go convierten el índice de tipo de bloque fuera de rango en un panic en vez de una escritura silenciosa fuera de límites, por lo que el modo de fallo en Go es una caída ante entrada del atacante, no la corrupción de memoria que permite la biblioteca C. Los servicios Go que descomprimen Brotli suministrado por atacantes deben igualmente pasar a 1.2.7 o posterior.
Fuera de la tabla, los proyectos que compilan su propia copia del decodificador heredan el fallo hasta actualizarlo, y un rastreador comunitario los sigue. Corregidos a 24 de octubre: la gema brotli 0.9.1 de Ruby, la extensión brotli 0.21.1 de PHP y UEFITool A76, todos con Brotli 1.2.1 incluido, además de MuPDF 1.28.x, cuya bifurcación de Brotli incorporó la corrección en abril. Aún sin versión corregida a 27 de octubre: ClickHouse, NanaZip, GraalJS (graal-nodejs), YDB y libjxl, que tienen la corrección integrada en sus ramas principales pero cuyas últimas versiones siguen incluyendo un decodificador afectado, y Apache Arrow, cuyo cambio C++ que exige versiones más recientes de Brotli, pull request #55167, seguía sin integrarse.
Una copia incluida llegó tarde y conviene identificarla con precisión porque una comprobación de versión no la detecta. Las compilaciones oficiales PHP para Windows de las versiones de seguridad del 21 de octubre, 8.5.12, 8.4.27, 8.3.36 y 8.2.35, incluían Brotli 1.2.0 en su inventario de componentes de software, y la extensión cURL puede alcanzarlo cuando una aplicación activa la descompresión automática de respuestas HTTP, que, según PHP Foundation, cURL desactiva por defecto pero las aplicaciones y bibliotecas cliente HTTP pueden habilitar. El 26 de octubre, el equipo PHP recompiló las cuatro como 8.5.12-1, 8.4.27-1, 8.3.36-1 y 8.2.35-1 con Brotli 1.2.1; el código fuente PHP no cambia, por lo que php -v imprime la misma versión antes y después, y la recompilación solo se identifica por el sufijo -1 del nombre del paquete y el SHA-256 de la página de descargas. Guzzle es la biblioteca cliente que cumple la condición de exposición de forma predeterminada: su controlador cURL establece CURLOPT_ENCODING en un valor vacío siempre que la opción decode_content no sea false, según su código en 7.16.1 y 8.3.1, y un valor vacío indica a cURL que acepte y descomprima todas las codificaciones que soporte.
Envoy e Istio están afectados cuando la descompresión Brotli está habilitada explícitamente, por ejemplo mediante un filtro descompresor de Envoy. Cuando está desactivada, el fallo no es alcanzable.
Compruebe qué ejecuta en hosts, contenedores e imágenes de CI:
node --version && node -p "process.versions.brotli" # Node.js: runtime and bundled decoder
bun --version # Bun 1.4.4+ is fixed
python -m pip show Brotli brotlicffi 2>/dev/null | grep -E '^(Name|Version)'
envoy --version # only meaningful with decompression enabled
istioctl version
curl -V | grep -o 'brotli/[0-9.]*' # brotli library linked into curl, e.g. brotli/1.1.0
go list -m all | grep brotli # Go: andybalholm/brotli 1.2.7+ is fixed
En Node.js, el archivo de bloqueo no responde a la pregunta: las aplicaciones decodifican Brotli mediante el módulo integrado node:zlib, que usa el decodificador incluido en el entorno de ejecución, por lo que la comprobación es la versión de Node.js anterior. El paquete npm brotli es una adaptación JavaScript independiente utilizada para fuentes WOFF2, no el decodificador C, y su presencia o ausencia en package-lock.json no indica nada sobre la exposición. En Python sí importan los requisitos fijados:
grep -iE '^(brotli|brotlicffi)' requirements.txt
El paquete Brotli de PyPI registró unos 82.8 millones de descargas al mes, por lo que esta dependencia está muy extendida en las pilas de aplicaciones y CI.
¿Cómo lo corrijo?
Actualice el decodificador en todos los lugares donde resida, reinicie el proceso y reconstruya las imágenes de contenedores: el proceso en ejecución conserva su decodificador antiguo en memoria hasta reiniciarse.
- Node.js: actualice a 26.12.1, 24.22.1 o 22.23.4 de las versiones de seguridad del 21 de octubre de 2026. Node.js 20.x ha llegado al final de su vida útil y no recibirá la corrección; migre esos despliegues a una rama con soporte.
- Bun: actualice a 1.4.4, publicada el 22 de octubre de 2026.
- Python: ejecute
pip install --upgrade Brotli brotlicffipara llegar a 1.2.1 y 1.2.1.0, y reconstruya las imágenes que fijen cualquiera de esos paquetes. - Go: actualice andybalholm/brotli a 1.2.7 o posterior en cualquier servicio que descomprima Brotli suministrado por atacantes.
- .NET: actualice a 8.0.33, 9.0.22, 10.0.14 o 11.0.0-rc.3.26522.148. La exposición necesita descompresión Brotli habilitada explícitamente o uso de las API Brotli sobre datos controlados por un atacante; .NET Framework no está afectado. Los despliegues autocontenidos y NativeAOT llevan su propia copia del entorno de ejecución, por lo que actualizar el entorno compartido de la máquina no los corrige: reconstruya y vuelva a desplegar las aplicaciones autocontenidas con el entorno actualizado, y vuelva a publicar las aplicaciones NativeAOT con el SDK corregido. Según el rastreador comunitario, las ramas públicas de GitHub aún no habían incorporado la corrección interna, por lo que las compilaciones desde el código de GitHub seguían afectadas.
- Envoy e Istio: actualice a las versiones corregidas de la tabla si su configuración habilita la descompresión Brotli.
- Google Brotli, si compila directamente contra él: 1.0.10, 1.1.1 o 1.2.1 según su rama.
- PHP en Windows: instale las recompilaciones -1, 8.5.12-1, 8.4.27-1, 8.3.36-1 o 8.2.35-1, de la página de descargas PHP y verifique el SHA-256, ya que
php -vno puede distinguirlas de las compilaciones del 21 de octubre. Hasta recompilar, la solución temporal en PHP es detener la descompresión automática: no establezcaCURLOPT_ENCODINGy, en Guzzle, establezca la opción de solicituddecode_contenten false, lo que detiene toda decodificación automática, por lo que las respuestas gzip también llegan comprimidas. - curl y otras herramientas que enlazan la biblioteca del sistema: actualice el paquete del sistema operativo. Debian corrigió brotli 1.1.0 para Debian 13 (trixie) el 23 de octubre de 2026 como 1.1.0-2+deb13u1; Amazon Linux 2023 aún indicaba sus paquetes brotli y Node.js 24 como pendientes de corrección a 22 de octubre de 2026, por lo que debe comprobar el estado de su distribución.
Si aún no puede actualizar, deje de decodificar Brotli no confiable. Las recomendaciones de la página de divulgación de OpenAI y de Aikido:
- Rechace las solicitudes entrantes con
Content-Encoding: brantes de que cualquier proxy o analizador decodifique el cuerpo. - Desactive la decodificación automática de Brotli en los clientes HTTP y rechace las respuestas Brotli antes de decodificarlas.
- En Python, desinstale los paquetes Brotli y brotlicffi para que los clientes recurran a gzip y deflate.
Exponga claramente los límites. Retirar br de la cabecera Accept-Encoding no ayuda por sí solo, porque un servidor puede enviar Brotli con independencia de lo solicitado por el cliente. Para Node.js en sí no se ha publicado una solución temporal general, de modo que actualizar el entorno de ejecución es la única corrección. Mientras tanto puede cerrarse una ruta entrante: los analizadores de Express 5 y body-parser 2 configurados con inflate: false rechazan cualquier cuerpo de solicitud comprimido con un error 415 antes de descomprimirlo, pero esto no protege las respuestas de fetch() ni otro código que decodifique Brotli. Un cortafuegos de aplicaciones web solo ayuda parcialmente: Vercel, que publicó reglas de cortafuegos el día de la divulgación, afirma que estas no cubren «las respuestas que sus funciones obtienen de otros servidores», una ruta que solo cierra la actualización del entorno de ejecución.
¿Cuál es la causa raíz?
El decodificador comunicaba un error de formato permanente como una condición recuperable de «se necesita más entrada», y la ruta de decodificación rápida descartaba incluso eso, por lo que la decodificación continuaba más allá del punto donde debía detenerse y escribía fuera de un búfer interno. El fallo está en DecodeBlockTypeAndLength, en c/dec/decode.c, y la corrección, el commit 0ed4268 de Evgenii Kliuchnikov del 27 de febrero de 2026, permite ver su funcionamiento.
Antes de la corrección, la función devolvía BROTLI_BOOL, el booleano de la biblioteca. BROTLI_FALSE significaba dos cosas muy distintas: un flujo mal formado y una lectura incompleta que podía resolverse con más entrada:
static BROTLI_INLINE BROTLI_BOOL DecodeBlockTypeAndLength(
int safe, BrotliDecoderState* s, int tree_type) {
...
if (max_block_type <= 1) {
- return BROTLI_FALSE;
max_block_type <= 1 significa que el flujo declara un único tipo de bloque, por lo que una orden de cambio de bloque en ese punto es entrada no válida, no una lectura pausada. Quien llamaba no podía distinguir ambos casos. En la ruta de procesamiento por flujo, Node.js describe la consecuencia: «un cambio de bloque no válido se comunicaba como necesidad temporal de más entrada en vez de como error de formato permanente, por lo que el decodificador seguía añadiendo bytes de entrada a un búfer interno de ocho bytes».
En la ruta rápida, el resultado se descartaba por completo. La variante insegura del cambio de bloque literal estaba declarada void, por lo que el fallo nunca llegaba al llamador:
-static void BROTLI_NOINLINE DecodeLiteralBlockSwitch(BrotliDecoderState* s) {
- DecodeLiteralBlockSwitchInternal(0, s);
La macro BROTLI_SAFE, utilizada en los tres puntos de llamada de cambio de bloque, comprueba el resultado en el modo seguro especulativo y lo ignora en modo inseguro. La corrección añade un comentario que lo expresa claramente: «en caso de ejecución 'insegura', cuando se garantiza entrada suficiente, se ignora el resultado». Esa garantía se cumplía con flujos bien formados, no con uno que contuviera un cambio de bloque no válido, por lo que la ruta rápida seguía decodificando con un estado obsoleto del búfer circular de tipos de bloque y del árbol Huffman, y las escrituras posteriores caían más allá del final de su búfer. El aviso de GitHub etiqueta el fallo como CWE-252, valor de retorno sin comprobar, y el propio desbordamiento es CWE-787, escritura fuera de límites.
¿Cómo se explota?
El ataque necesita una ruta de entrega donde el objetivo descomprima Brotli controlado por el atacante y un flujo manipulado. Paso a paso:
- El atacante construye un flujo Brotli que alcanza
DecodeBlockTypeAndLengthcon una orden de cambio de bloque mientras el flujo declara un solo tipo de bloque para ese árbol. - El flujo se entrega como respuesta
Content-Encoding: bra una llamadafetch(), como cuerpo de solicitud comprimido con Brotli analizado por Express 5 o body-parser 2, mediante un filtro de descompresión de Envoy o Istio, o como respuesta decodificada automáticamente por un cliente HTTP Python con Brotli instalado. - El cambio de bloque no válido devuelve
BROTLI_FALSE. La ruta por flujo lo interpreta como «dame más bytes»; la ruta rápida lo descarta. En ambas, la decodificación continúa en vez de rechazar el flujo. - La decodificación con un estado obsoleto de tipos de bloque escribe datos influenciados por el atacante más allá del final de un búfer interno del decodificador y corrompe la memoria adyacente del proceso.
- La corrupción hace caer el proceso, divulga memoria o redirige la ejecución. El equipo rojo de Imperva, que denominó su trabajo Node2Shell, ejecutó código suministrado por el atacante en una compilación Node.js 24.22.0 sin modificar para Linux ARM64, entregando la carga tanto como respuesta obtenida como cuerpo de solicitud Express. El exploit necesitó varios intentos, no se ha publicado y no se probó en otras compilaciones.
El equipo Codex Security de OpenAI, que comunicó el fallo, describe la exposición como bidireccional: «un servidor sin corregir que acepte entrada comprimida podría ser controlado por un cliente malicioso, y un cliente sin corregir que acepte entrada comprimida (como 'curl --compressed') podría ser controlado por un servidor malicioso».
¿Cómo transcurre el ataque?
El flujo es breve: entregar un flujo manipulado mediante cualquier ruta de decodificación Brotli, dejar que el error ambiguo mantenga activo el decodificador tras un cambio de bloque no válido y hacer que las escrituras siguientes caigan fuera del búfer.
una orden de cambio de bloque no válida"] --> B["Entregado mediante respuesta fetch,
cuerpo de solicitud o filtro proxy"] B --> C["El decodificador encuentra el cambio no válido:
error de formato, no falta de entrada"] C --> D["El booleano TRUE o FALSE confunde
ambos casos: falla el informe de errores"] D --> E["La ruta rápida descarta el resultado
y sigue decodificando"] E --> F["El estado obsoleto de tipo de bloque provoca
escrituras más allá del final del búfer"] F --> G["Caída, divulgación de memoria
o ejecución de código"]
¿Qué puede hacer un atacante?
- Hacer caer el proceso decodificador. La denegación de servicio es el resultado más fiable, ya que la corrupción del montón suele causar una caída antes de que ocurra otra cosa.
- Divulgar memoria del proceso. El estado adyacente del decodificador y el contenido del montón pueden filtrarse a través de resultados de decodificación corruptos.
- Ejecutar código. Imperva lo demostró en una compilación Node.js; la fiabilidad depende de la disposición del montón del proceso, razón por la que la demostración necesitó varios intentos y no existe un exploit público fiable, según Red Hat.
- Comprometer clientes además de servidores. Un cliente sin corregir que decodifique Brotli de un servidor malicioso o comprometido está expuesto del mismo modo, una ruta que la mayoría de las medidas de endurecimiento del servidor no cubre.
Condiciones que necesita el atacante: una ruta de decodificación de Brotli controlado por él, como las enumeradas, y nada más. Ninguna autenticación aparte de la del intercambio HTTP portador, y ninguna interacción del usuario para la decodificación en el servidor.
¿Por qué funciona la corrección?
El commit 0ed4268, «Detectar y comunicar antes los flujos no válidos», reconstruye la gestión de errores para que los dos estados dejen de reducirse a un único booleano:
DecodeBlockTypeAndLengthdevuelve ahoraBrotliDecoderErrorCode, con tres estados: éxito, error definitivo o necesidad de más entrada.- El caso de cambio de bloque no válido devuelve un nuevo error permanente,
BROTLI_DECODER_ERROR_FORMAT_BLOCK_SWITCH, código -17, que la cabecera antes dejaba como «reservado». - Los casos de lectura incompleta devuelven separadamente
BROTLI_DECODER_NEEDS_MORE_INPUT, por lo que el bucle por flujo conserva su comportamiento legítimo de reanudación. - Una nueva macro
BROTLI_SAFE_WITH_STATUScomprueba el estado tanto en rutas seguras como inseguras y salta asaveStateAndReturnen caso de fallo, por lo que la ruta rápida ya no puede ignorar un error de cambio de bloque:
+#define BROTLI_SAFE_WITH_STATUS(METHOD) \
+ { \
+ BrotliDecoderErrorCode status; \
+ if (safe) { \
+ status = Safe##METHOD; \
+ } else { \
+ status = METHOD; \
+ } \
+ if (status != BROTLI_DECODER_SUCCESS) { \
+ result = status; \
+ goto saveStateAndReturn; \
+ } \
+ }
Los tres puntos de llamada de cambio de bloque usan ahora la macro que comprueba el estado, y el parche añade una aserción de depuración sobre el invariante de longitud del metabloque. La corrección es completa para este fallo: un cambio de bloque no válido es ahora un error permanente comunicado en todas las rutas.
La lección de despliegue importa tanto como el código. La corrección llegó al código fuente de google/brotli el 27 de febrero de 2026, y ninguna versión de Brotli la incluyó hasta el 21 de octubre de 2026. Según OpenAI, la causa raíz «se corrigió realmente en el código fuente de Brotli en febrero, pero entonces no se sabía que originaba una vulnerabilidad de seguridad y no había una versión más reciente de Brotli». Cada entorno y paquete tuvo después que publicar su propia copia de la corrección en octubre, por lo que las versiones corregidas anteriores abarcan tres días y ocho ecosistemas.
¿Cómo compruebo si me comprometieron?
No se ha comunicado explotación en ataques reales y no hay indicadores de compromiso para este fallo. La evaluación de CISA del 23 de octubre de 2026 registró explotación «none» y automatización «no».
Qué buscar en términos generales hasta que eso cambie: grupos de caídas en procesos Node.js, Bun, Envoy o Istio que manejen tráfico codificado con Brotli, anomalías de contenido de memoria en sus volcados de fallo y, si hubo ejecución de código en un host, los artefactos habituales a nivel de proceso, como procesos hijos inesperados y conexiones salientes. Cualquier hallazgo así en una ruta de decodificación Brotli merece tratarse como relacionado hasta demostrar lo contrario, y la respuesta es la estándar ante sospecha de ejecución de código: aislar, tomar una instantánea, rotar las credenciales accesibles desde el proceso y reconstruir desde una imagen limpia.
Cronología
- 2026-02-27: el commit
0ed4268llega a google/brotli con la corrección; no se publica una versión después y aún no se reconoce el impacto de seguridad. - 2026-10-21: Node.js publica 26.12.1, 24.22.1 y 22.23.4, y google/brotli publica 1.0.10, 1.1.1 y 1.2.1.
- 2026-10-22: se publica CVE-2026-111497 con puntuación CVSS v4.0 9.2; se lanza Bun 1.4.4; se publica el aviso de GitHub GHSA-9v8h-qqgm-4m35 para los paquetes Python.
- 2026-10-23: se comunica la demostración Node2Shell de Imperva; CISA registra ausencia de explotación; el aviso de GitHub se actualiza para vincular brotli de pip anterior a 1.2.1 y brotlicffi anterior a 1.2.1.0; Debian corrige el paquete brotli de trixie; se añaden PYSEC-2026-4322 y PYSEC-2026-4323; Andy Balholm adapta la corrección al decodificador Go como commit 33c2a988 y la publica como andybalholm/brotli v1.2.7.
- 2026-10-24: se publican matrices de versiones afectadas entre ecosistemas.
- 2026-10-25: Microsoft publica el aviso .NET GHSA-p3jp-9v83-76w9, que corrige 225 paquetes NuGet de .NET 8, 9, 10 y las candidatas de 11; el rastreador comunitario registra las correcciones del 24 de octubre de la gema brotli de Ruby, la extensión brotli de PHP y UEFITool.
- 2026-10-26: PHP recompila sus paquetes oficiales Windows como 8.5.12-1, 8.4.27-1, 8.3.36-1 y 8.2.35-1 con Brotli 1.2.1, cinco días después de que las compilaciones del 21 de octubre incluyeran Brotli 1.2.0 en sus SBOM.
- 2026-10-25: este artículo, actualizado el 27 de octubre con las recompilaciones PHP para Windows, la condición de exposición de Guzzle y el estado de Apache Arrow.
Preguntas frecuentes
¿Está expuesto un servidor HTTP básico de Node.js?
Un servidor básico de Node.js no decodifica por sí mismo los cuerpos de solicitudes, por lo que queda fuera de las rutas demostradas. La exposición aparece cuando analiza cuerpos Brotli mediante Express 5 o body-parser 2, cuando llama a fetch() y decodifica una respuesta Content-Encoding: br, o cuando su código pasa datos no confiables a zlib.brotliDecompress(), zlib.createBrotliDecompress() u otras API Brotli de node:zlib, por ejemplo en un controlador WebSocket, un flujo RPC o una canalización de procesamiento de archivos. Si nada de esto ocurre en su código, sigue siendo conveniente actualizar el entorno según lo previsto.
¿Retirar br de Accept-Encoding protege a mis clientes?
No. Un servidor puede enviar Brotli independientemente de lo solicitado por el cliente, y los clientes Python decodifican Brotli automáticamente cuando está instalado el paquete. Desactive la decodificación automática Brotli en la configuración del cliente, rechace las respuestas Brotli antes de decodificarlas o desinstale los paquetes Python para que los clientes recurran a gzip y deflate.
¿Por qué la corrección tardó de febrero a octubre en llegar a los usuarios?
El cambio llegó al código fuente de google/brotli el 27 de febrero de 2026, pero el proyecto no publicó ninguna versión desde esa fecha hasta la respuesta de seguridad de octubre, y entonces no se conocía el impacto de seguridad del cambio. Los entornos que incorporan el decodificador, incluidos Node.js y Bun, no podían adoptar la corrección hasta que existiera una versión que incorporar.
¿Mi escáner de dependencias marcará los paquetes Python?
El aviso de GitHub vincula ahora brotli de pip anterior a 1.2.1 y brotlicffi anterior a 1.2.1.0, actualizado el 23 de octubre de 2026, y existen las entradas PYSEC-2026-4322 y PYSEC-2026-4323, por lo que las herramientas que sincronizan sus bases de datos pueden marcarlos. Las herramientas desactualizadas o aisladas pueden ir por detrás, de modo que comprobar manualmente las versiones instaladas, como arriba, es la prueba fiable esta semana.
¿Envoy e Istio están expuestos de forma predeterminada?
No. Ambos están afectados cuando la descompresión Brotli está habilitada explícitamente, por ejemplo mediante un filtro descompresor de Envoy. Si su configuración nunca descomprime Brotli, el fallo no es alcanzable; si lo hace, corresponden las versiones corregidas de la tabla.
¿Qué ocurre con curl y otras herramientas del sistema?
curl y muchas otras herramientas enlazan la biblioteca Brotli del sistema operativo en vez de incluirla. curl -V muestra la versión enlazada, por ejemplo brotli/1.1.0. Actualice mediante la distribución: Debian publicó el paquete corregido de trixie el 23 de octubre de 2026, y otras distribuciones lo hacen según sus propios calendarios.
Encuentre el decodificador antiguo antes que un atacante
Analice sus repositorios, imágenes de contenedores y servicios expuestos a Internet con Ostorlab para detectar todos los despliegues Node.js, Bun y Python que aún incluyan un decodificador Brotli anterior a las correcciones del 21 de octubre de 2026.
Referencias
- Registro CVE-2026-111497 con el vector CVSS v4.0 9.2 y el rango afectado de 1.0.3 a 1.2.0: https://cveawg.mitre.org/api/cve/CVE-2026-111497 (consultado el 25 de octubre de 2026)
- Versiones de seguridad de Node.js del 21 de octubre de 2026, con descripción por fallo, ramas afectadas, versiones corregidas y créditos (informantes Khai Tran y Sylvie Mayer de OpenAI Codex Security; responsables de la corrección Matteo Collina y Antoine du Hamel): https://nodejs.org/en/blog/vulnerability/october-2026-security-releases (consultadas el 25 de octubre de 2026)
- Commit de corrección 0ed4268, «Detectar y comunicar antes los flujos no válidos», Evgenii Kliuchnikov, 27 de febrero de 2026: https://github.com/google/brotli/commit/0ed4268 (consultado el 25 de octubre de 2026)
- Versiones de google/brotli 1.0.10, 1.1.1 y 1.2.1, publicadas el 21 de octubre de 2026: https://github.com/google/brotli/releases (consultadas el 25 de octubre de 2026)
- GHSA-9v8h-qqgm-4m35, aviso revisado que vincula brotli y brotlicffi de pip, con CWE-252: https://github.com/advisories/GHSA-9v8h-qqgm-4m35 (consultado el 25 de octubre de 2026; vinculación de PyPI añadida en la actualización del 23 de octubre de 2026)
- Publicación de Bun 1.4.4, 22 de octubre de 2026: https://github.com/oven-sh/bun/releases/tag/bun-v1.4.4 (consultada el 25 de octubre de 2026)
- Commit de corrección de andybalholm/brotli 33c2a988, «Detectar y comunicar antes los flujos no válidos», adaptación de la corrección Google, 23 de octubre de 2026, publicado como v1.2.7: https://github.com/andybalholm/brotli/commit/33c2a988 y https://github.com/andybalholm/brotli/releases/tag/v1.2.7 (consultados el 26 de octubre de 2026)
- Aviso .NET de Microsoft GHSA-p3jp-9v83-76w9, CVE-2026-111497, 225 paquetes NuGet corregidos en 8.0.33, 9.0.22, 10.0.14 y 11.0.0-rc.3.26522.148, con la condición previa de descompresión automática y la declaración de que .NET Framework no está afectado: https://github.com/dotnet/runtime/security-advisories/GHSA-p3jp-9v83-76w9 y https://github.com/dotnet/announcements/issues/494 (consultados el 26 de octubre de 2026)
- Rastreador comunitario Broccoli2Shell de copias incluidas, estado de la prueba de concepto pública del 22 de octubre (caída y lectura limitada de memoria en compilaciones estándar, ejecución de código solo en una compilación deliberadamente debilitada) y estado de corrección por proyecto: https://broccoli2shell.com/ (consultado el 26 de octubre de 2026)
- Aviso de Envoy GHSA-3wvj-j6qm-62mr: https://github.com/envoyproxy/envoy/security/advisories/GHSA-3wvj-j6qm-62mr (consultado el 25 de octubre de 2026)
- Aviso de seguridad de Istio 2026-007: https://istio.io/latest/news/security/istio-security-2026-007/ (consultado el 25 de octubre de 2026)
- Aviso de cdxgen GHSA-5266-jm88-3grm: https://github.com/cdxgen/cdxgen/security/advisories/GHSA-5266-jm88-3grm (consultado el 25 de octubre de 2026)
- The Hacker News, «El fallo del decodificador Brotli detrás de la RCE de Node.js también afecta a Bun, Python y otro software muy utilizado», 24 de octubre de 2026, con la matriz de afectados, la cita bidireccional de OpenAI, las evaluaciones de CISA y Red Hat y las recomendaciones temporales: https://thehackernews.com/2026/10/brotli-decoder-flaw-behind-nodejs-rce.html (consultado el 25 de octubre de 2026)
- The Hacker News sobre la demostración Node2Shell de Imperva, 23 de octubre de 2026: https://thehackernews.com/2026/10/researchers-demonstrate-node2shell-rce.html (consultado el 25 de octubre de 2026)
- Página de divulgación de OpenAI sobre el fallo, patchtheplanet.org: https://patchtheplanet.org/brotli (referenciada por The Hacker News, 24 de octubre de 2026; la página no se renderiza como texto estático desde este entorno)
- Evaluación CVE de Red Hat, con puntuación 8.1 y observación de que no hay una prueba de concepto pública fiable: https://access.redhat.com/security/cve/CVE-2026-111497 (referenciada por The Hacker News, 24 de octubre de 2026)
- Boletín de seguridad Node.js de Vercel sobre los límites de sus reglas de cortafuegos: https://vercel.com/kb/bulletin/node-js-security-advisory (referenciado por The Hacker News, 24 de octubre de 2026)
- Anuncio de seguridad de Debian para brotli 1.1.0-2+deb13u1, 23 de octubre de 2026: https://lists.debian.org/debian-security-announce/2026/msg00498.html (referenciado por The Hacker News, 24 de octubre de 2026)
- Estadísticas de descargas de Brotli en PyPI, unos 82.8 millones al mes: https://pypistats.org/packages/brotli (consultadas el 25 de octubre de 2026)
- Análisis de Aikido sobre la exposición de los paquetes Python y las soluciones temporales: https://www.aikido.dev/blog/python-packages-vulnerable-node2shell-brotli-cve-2026-111497 (referenciado por The Hacker News, 24 de octubre de 2026)
- PHP Foundation, «Compilaciones PHP para Windows actualizadas para la corrección de seguridad de Brotli», 26 de octubre de 2026: las recompilaciones -1 de 8.5.12, 8.4.27, 8.3.36 y 8.2.35 con Brotli 1.2.1, la accesibilidad mediante descompresión automática de cURL y el significado del sufijo -1: https://www.php.net/archive/2026.php#2026-10-26-1 (consultado el 27 de octubre de 2026)
- The Hacker News, «PHP publica su segunda actualización de seguridad para Windows en cinco días para corregir un fallo de ejecución de código de Brotli», 26 de octubre de 2026, con las pruebas SBOM de Brotli 1.2.0 en las compilaciones del 21 de octubre, el hallazgo de configuración predeterminada de Guzzle en su código 7.16.1 y 8.3.1 y las recomendaciones temporales de OpenAI: https://thehackernews.com/2026/10/php-issues-second-windows-security.html (consultado el 27 de octubre de 2026)
- Código del controlador cURL de Guzzle, 7.16.1,
src/Handler/CurlFactory.php, que estableceCURLOPT_ENCODINGen un valor vacío salvo quedecode_contentsea false: https://github.com/guzzle/guzzle/blob/7.16.1/src/Handler/CurlFactory.php (consultado el 27 de octubre de 2026) - Pull request #55167 de Apache Arrow, «GH-55165: [C++] Exigir versiones más recientes de Brotli», aún abierto a 27 de octubre de 2026: https://github.com/apache/arrow/pull/55167 (consultado el 27 de octubre de 2026)