sistema: OPERATIVO
← volver a todos los hacks
INFRASTRUCTURE MEDIUM NEW

Un parche incompleto: las fugas de direcciones de memoria vuelven en las rutas nuevas de vLLM

El parche del fallo crítico de análisis de imágenes en vLLM saneó el enrutador de OpenAI, pero rutas añadidas semanas después siguen devolviendo el texto bruto de las excepciones, filtrando direcciones de montículo y reabriendo una primitiva de evasión de ASLR.

2026-07-17 // 7 min affects: vllm, vllm-<=0.22.0, anthropic-api-router, speech-to-text-realtime, multimodal-endpoints

¿Qué es esto?

El 11 de junio de 2026, el proyecto vLLM publicó un aviso de seguridad (GHSA-hgg8-fqqc-vfmw) reportado por el investigador Kai Aizen (SnailSploit). Documenta un parche incompleto: la corrección que cerró un fallo crítico anterior de análisis de imágenes en el enrutador compatible con OpenAI de vLLM no se extendió a las rutas añadidas poco después, de modo que esos nuevos puntos de entrada siguen filtrando direcciones de memoria internas a quienes llaman de forma remota.

El fallo original era grave: una vulnerabilidad crítica (CVSS 9.8) que encadenaba una fuga de dirección de memoria con un desbordamiento de montículo de una biblioteca de imágenes para lograr ejecución remota de código. Su corrección introdujo un saneador que elimina las direcciones de las representaciones de objetos en los mensajes de error antes de que lleguen al cliente. Este nuevo hallazgo se clasifica como medio (CVSS 3.1 base 5.3), con bajo impacto en la confidencialidad y ninguno en la integridad o la disponibilidad. La clase de debilidad es CWE-532, inserción de información sensible en un mensaje de error, la misma clase que el fallo original. El código afectado está presente en las versiones de vLLM hasta la 0.22.0 inclusive.

Cómo funciona

Cuando vLLM analiza una imagen malformada, la biblioteca de imágenes lanza un error cuyo texto contiene la representación en memoria del objeto búfer, algo como cannot identify image file <_io.BytesIO object at 0x7a95e299e750>. Ese valor hexadecimal final es una dirección de montículo activa. Si llega al cliente tal cual, un atacante averigua dónde residen los objetos en el espacio de direcciones del proceso, reduciendo la entropía del ASLR de unos cuatro mil millones de posibilidades a un puñado, exactamente el paso de reconocimiento en el que se apoyaba la cadena crítica original.

La corrección original añadió una función auxiliar sanitize_message y la conectó a los manejadores de excepciones del enrutador de OpenAI, reescribiendo <_io.BytesIO object at 0x...> como <_io.BytesIO object>. El problema es que varias rutas de respuesta añadidas en el mismo momento o después nunca la invocan. El aviso enumera cinco de esos puntos: el endpoint de «mensajes» compatible con Anthropic, su endpoint de conteo de tokens, el conversor de flujo server-sent-events y dos rutas de error del WebSocket de reconocimiento de voz en tiempo real. Cada uno devuelve str(exception) directamente a quien llama.

Surge una pregunta natural: ¿por qué el manejador de excepciones global y saneador de vLLM no intercepta estos casos? La respuesta reside en un detalle sutil del framework que conviene interiorizar: un manejador de excepciones global solo se activa ante excepciones no gestionadas que se propagan fuera de una ruta. En cambio, cada ruta HTTP afectada captura la excepción dentro de la función de ruta y construye su propia respuesta, por lo que el manejador saneador nunca se invoca. Las rutas WebSocket lo eluden por otro motivo: las tramas WebSocket no atraviesan en absoluto la cadena de manejo de excepciones HTTP. El mismo desencadenante de imagen malformada que alimentaba el fallo original alcanza todas estas rutas nuevas sin cambios.

El aviso es explícito: no se trata de código heredado obsoleto, sino de una serie de omisiones de alcance. El saneador llegó el 9 de enero de 2026; el enrutador de Anthropic se añadió seis días después sin él, el endpoint de conteo de tokens unos dos meses más tarde, y las rutas de reconocimiento de voz en mayo, replicando cada una el patrón sin sanear.

Por qué importa

Por sí sola, una fuga de dirección no cambia nada que el usuario pueda ver. Su valor está en ser una pieza de construcción. La cadena original necesitaba precisamente esta primitiva para vencer al ASLR antes de desencadenar una corrupción de memoria. Esa segunda etapa —un desbordamiento de montículo en un códec de imágenes antiguo— está corregida en las versiones recientes de las bibliotecas, así que en una pila totalmente actualizada este hallazgo es una primitiva de divulgación de información y no una vía hacia la ejecución de código. Pero vLLM se distribuye a menudo dentro de imágenes Docker personalizadas, reconstrucciones derivadas y distribuciones LTS de larga vida que fijan bibliotecas de sistema antiguas. En cualquier despliegue que aún incorpore un códec de imágenes vulnerable, estos nuevos puntos de entrada reactivan en silencio la cadena completa de «fuga y luego corrupción» que el parche inicial debía cerrar.

La lección más amplia trata de cómo se degradan las correcciones. Un parche aplicado en puntos de llamada concretos solo protege esos puntos de llamada. A medida que se añaden nuevas rutas, transportes y endpoints, estos reintroducen el mismo patrón que la corrección debía eliminar, a menos que la mitigación resida en un punto de paso obligado por el que transite toda respuesta.

Defensas

La corrección definitiva consiste en actualizar a una versión de vLLM que incluya la remediación fusionada en la pull request de corrección del proyecto. Más allá de actualizar, las recomendaciones del aviso se generalizan bien y coinciden con la guía de OWASP sobre divulgación de información sensible:

  1. Sanee la salida de error de forma simétrica. Toda ruta que devuelva texto de excepción a un cliente —rutas HTTP, conversores de flujo y manejadores WebSocket— debe depurar las representaciones de objetos y las direcciones brutas. Una corrección en un solo enrutador no es una corrección en todas partes.
  2. Traslade la mitigación a un punto de paso obligado. Los bloques try/except locales a una ruta y los manejadores WebSocket eluden los manejadores de excepciones del framework. Un middleware de respuesta que depure todo cuerpo de error saliente previene toda esta clase de regresión, de modo que una ruta recién añadida no pueda reabrir la fuga en silencio.
  3. Amplíe el patrón de depuración. Una expresión regular que solo coincida con el sufijo de dirección exacto de CPython en minúsculas es frágil; futuros entornos de ejecución, extensiones en C o métodos __repr__ personalizados pueden producir formatos que no coincidan. Elimine cualquier dirección hexadecimal aislada en lugar de una forma concreta.
  4. Nunca devuelva errores internos brutos a quienes llaman sin confianza. Registre la excepción detallada en el servidor; devuelva al cliente un error genérico y opaco. Las fugas de direcciones, las trazas de pila y las rutas de archivos son todo reconocimiento.
  5. Trate los seguimientos de parches incompletos como prioritarios. Cuando se corrige un fallo crítico, audite cada ruta hermana y cada ruta recién añadida en busca del mismo punto de salida antes de dar el caso por cerrado.

Estado

ElementoReferenciaFechaNotas
Aviso de seguimiento publicadoGHSA-hgg8-fqqc-vfmw2026-06-11Divulgación de información (CWE-532); CVSS 5.3 medio; sin CVE asignado
Vulnerabilidad originalCVE-2026-22778 / GHSA-4r2x-xpjr-7cvv2026Crítica (CVSS 9.8); fuga encadenada a un desbordamiento de montículo para RCE
Saneador introducidovLLM PR #319872026-01-09Aplicado solo al enrutador de OpenAI
Versiones afectadasvLLM ≤ 0.22.0Enrutador de Anthropic, conteo de tokens, conversor SSE, WebSocket de voz
CorrecciónvLLM PR #451192026Aplica el saneamiento a los puntos omitidos

La conclusión es una vieja máxima en un escenario nuevo: un parche vale solo lo que cubre su superficie. Sanee la salida de error en un único punto por el que fluya toda respuesta, mantenga el estado interno bruto fuera de los mensajes destinados al cliente y, cuando corrija un fallo crítico, rastree cada ruta que comparta su punto de salida antes de declararlo cerrado.

Los detalles proceden del aviso de seguridad de vLLM y de las pull requests referenciadas. No se reproduce ningún payload de demostración; los defensores deben consultar el aviso enlazado para evaluar su exposición.

Sources