# Modelo de amenazas — CVE-2026-111497 (escritura fuera de límites en el decodificador de Brotli)

Este documento define qué considera expuesto la herramienta, qué no cubre de forma explícita y por
qué la clasificación se traza donde se traza. Es la referencia para interpretar cada veredicto que
devuelven los scripts.

## 1. La vulnerabilidad

| Propiedad | Valor |
|---|---|
| Identificador | CVE-2026-111497 |
| Componente | Google Brotli, decodificador (`c/dec/decode.c`) |
| Debilidad | CWE-787, escritura fuera de límites |
| Versiones upstream vulnerables | 1.0.3 … 1.0.9, 1.1.0, 1.2.0 |
| Versiones upstream corregidas | 1.0.10, 1.1.1, 1.2.1 (21 de octubre de 2026) |
| Vector de ataque | flujo Brotli manipulado entregado al decodificador |
| Autenticación requerida | no |
| Impacto | caída del proceso, corrupción de memoria y, en algunas configuraciones, ejecución remota de código |
| Gravedad | CVSS 4.0 9.2 según la publicación del proyecto; 8.5 en la escala CVSS 3.x de los rastreadores de distribución |

La ruta defectuosa es la máquina de estados del decodificador en una transición de bloque: un flujo
malformado lleva los contadores internos más allá del límite previsto y el decodificador escribe
fuera del búfer de salida reservado en lugar de señalar antes que el flujo es inválido. La
corrección upstream detecta y señala el flujo inválido antes de la escritura.

## 2. Qué está expuesto y qué no

La distinción que decide la mayoría de los veredictos:

- Un **codificador** (nginx `ngx_brotli`, `mod_brotli`, canalizaciones de activos estáticos) comprime
  datos que el propio servidor produjo. Nunca analiza Brotli controlado por el atacante. No es la
  superficie de ataque, aunque enlace el mismo paquete.
- Un **decodificador** acepta datos del exterior y los analiza. Esa es la superficie de ataque.

| Ruta | Expuesta cuando | Notas |
|---|---|---|
| Cuerpo de petición HTTP | la aplicación o un proxy descomprime `Content-Encoding: br` | el vector de mayor impacto donde existe |
| Cliente HTTP saliente | libcurl con `CURLOPT_ENCODING` vacío, `fetch` de Node, `httpx`/`requests` de Python con Brotli | un tercero malicioso o comprometido responde con `br` |
| Cadena de respuesta a través de un proxy | descompresor HTTP de Envoy/Istio habilitado | el proxy pasa a ser el decodificador |
| Carga o importación de archivos | la aplicación descomprime flujos o archivos Brotli | a menudo se pasa por alto en las auditorías |
| Runtime empaquetado | descompresión de peticiones de Node.js, Bun, .NET | la corrección llega con el runtime, no con `libbrotli1` |

## 3. Por qué libcurl domina en las flotas reales

Medido en tres hosts de producción: el vector alcanzable nunca fue «las peticiones al servidor web»,
porque nginx y Apache usaban Brotli solo para comprimir y ninguno descomprimía cuerpos de petición.
La ruta dominante era **HTTP saliente a través de libcurl**, alcanzada desde código PHP de la
aplicación.

`CURLOPT_ENCODING` con una cadena vacía indica a libcurl que anuncie y acepte todas las
codificaciones que soporta, incluida `br`. Ese único argumento aparece en:

- `wp-includes/Requests/src/Transport/Curl.php` de WordPress;
- `File.php` de SimplePie en WordPress;
- las factorías de manejadores de Guzzle incluidas dentro de plugins;
- el tráfico directo de `wp_remote_*`, la lectura de RSS y las llamadas a la API de proveedores.

En un host el inventario contó 164 archivos PHP que llevaban `CURLOPT_ENCODING` o
`CURLOPT_ACCEPT_ENCODING`. Esa cifra es la medida real de la exposición en una máquina de
alojamiento compartido, no la mera presencia del paquete.

## 4. Modelo del atacante

| Posición del atacante | Capacidad | Consecuencia |
|---|---|---|
| Remoto, sin autenticación | envía un cuerpo Brotli manipulado o sirve una respuesta `br` manipulada | caída, corrupción de memoria y posible ejecución de código en el proceso que decodifica |
| Proveedor de contenido externo | controla un servicio que el servidor consulta | alcanza la ruta de decodificación de libcurl sin tocar el perímetro |
| Local sin privilegios | entrega un archivo que la aplicación descomprime | el mismo decodificador, con menor impacto |

La herramienta asume que el atacante puede elegir los bytes y no puede elegir el proceso: el
objetivo de la auditoría es asegurar que no queda ningún decodificador alcanzable en un proceso
vulnerable.

## 5. Estrategia de detección

La presencia de un paquete no es exposición. Por eso el detector registra cuatro hechos
independientes y clasifica solo cuando se conocen los cuatro:

1. la versión instalada, con el epoch y la revisión de la distribución eliminados hasta el número
   upstream;
2. si el changelog empaquetado ya menciona el CVE (backport de la distribución aplicado);
3. si el candidato de apt es más reciente que la versión instalada (existe una corrección
   soportada);
4. qué procesos en ejecución mapean `libbrotlidec`, y a través de qué runtime.

Un host es `VULNERABLE` solo cuando la versión upstream está en el rango vulnerable **y** no hay
backport. Un host es `SAFE` cuando falla cualquiera de las dos condiciones, incluido el caso de una
revisión de distribución que conserva el número upstream de aspecto vulnerable pero lleva la
corrección.

## 6. Fuera de alcance

| Área | Motivo |
|---|---|
| Copias enlazadas estáticamente | invisibles para `dpkg`; exigirían escaneo binario archivo por archivo |
| Imágenes de contenedor | requieren escaneo del lado del registro, no inspección del host |
| Envoy, Istio, .NET, Bun, Deno | ciclos de remediación propios; documentados, no automatizados |
| Hosts Windows y macOS | la herramienta es solo bash y apt |
| Mitigaciones a nivel de aplicación | bloquear `Content-Encoding: br` es un paliativo que aplica el operador, no una corrección |

## 7. Riesgo residual tras la remediación

1. Los procesos de escritorio e infraestructura mantienen mapeada la biblioteca antigua hasta el
   siguiente inicio de sesión o reinicio. No son una ruta de decodificación de servidor; el detector
   los informa como `deferred`.
2. Un proceso iniciado desde un paquete instalado **después** de la remediación pero antes de
   sustituir la biblioteca heredaría la biblioteca parcheada; el orden interno de `remediate.sh`
   evita el caso contrario.
3. El código de aplicación que incluye su propia copia de Brotli (fuentes vendorizadas, compilación
   estática) no se ve afectado por la actualización del paquete y debe recompilarse por separado.

Véase [PLAYBOOK.es.md](PLAYBOOK.es.md) para el procedimiento y [FIELD-REPORT.es.md](FIELD-REPORT.es.md)
para cómo se comportaron estos tres hechos en hosts reales.
