Descripción general

Se ha identificado una vulnerabilidad de tipo ReDoS (Regular Expression Denial of Service) en vLLM que afecta al parámetro de API structured_outputs.regex. El problema reside en que la cadena de expresión regular suministrada por el usuario se pasa directamente a los compiladores de gramática de los backends xgrammar y outlines sin ningún mecanismo de timeout ni análisis de complejidad. Un atacante puede enviar una única petición con un patrón adversarial y bloquear indefinidamente el worker de inferencia, provocando una condición de DoS.

Causa raíz

El problema se manifiesta en dos backends de forma independiente.

Backend xgrammar

En backend_xgrammar.py, línea 91, la llamada a compile_regex() no dispone de ningún mecanismo de guarda ni límite temporal:

python
ctx = self.compiler.compile_regex(grammar_spec)

Cualquier patrón que provoque una explosión en el espacio de estados del autómata finito determinista (DFA) bloqueará este hilo sin posibilidad de recuperación automática.

Backend outlines

En backend_outlines.py, líneas 299 a 330, la función validate_regex_is_buildable() realiza únicamente comprobaciones estructurales superficiales:

python
def validate_regex_is_buildable(regex: str) -> None:
    sre_parse.parse(regex)   # Solo parseo AST, no detecta patrones exponenciales
    _check_unsupported(...)  # Bloquea lookarounds y backrefs, no cuantificadores anidados

Esta función bloquea lookarounds y backreferences, pero no realiza ningún análisis de complejidad. Los patrones con cuantificadores anidados, como (a+)+b, superan todas las validaciones sin problema.

Además, en backend_outlines.py, línea 64, la construcción del índice tampoco dispone de timeout:

python
oc.Index(regex_string, vocabulary.inner)

Mecanismo de explotación

Un atacante con acceso a la API de vLLM puede enviar una petición con un patrón de expresión regular diseñado para provocar una explosión exponencial en el número de estados del DFA durante la compilación. Patrones como (a+)+b pasan todas las validaciones estructurales implementadas actualmente y, sin embargo, generan un número exponencial de estados internos durante la compilación, lo que hace que el proceso de compilación no termine en un tiempo razonable. El worker de inferencia queda bloqueado indefinidamente, impidiendo que procese cualquier otra petición.

Impacto

La explotación de esta vulnerabilidad produce una condición de DoS. Un único atacante con acceso a la API puede bloquear permanentemente un worker de inferencia con una sola petición maliciosa. Dado que vLLM se utiliza habitualmente como backend de inferencia para modelos de lenguaje de gran escala (LLM) en entornos de producción, el impacto operativo puede ser significativo: degradación total del servicio de inferencia, necesidad de reinicio manual del proceso afectado y posible efecto en cascada si el sistema de orquestación no detecta y reemplaza el worker bloqueado.

Remediación recomendada

Se recomienda aplicar las siguientes medidas correctivas:

  1. Envolver las llamadas a compile_regex() y a oc.Index() en un hilo con un plazo de ejecución máximo. Un timeout de 5 segundos es un valor razonable como punto de partida:
python
import concurrent.futures

def compile_with_timeout(compiler, grammar_spec, timeout=5):
    with concurrent.futures.ThreadPoolExecutor(max_workers=1) as executor:
        future = executor.submit(compiler.compile_regex, grammar_spec)
        return future.result(timeout=timeout)
  1. Añadir un análisis de complejidad a validate_regex_is_buildable() que detecte patrones con cuantificadores anidados antes de que lleguen a la fase de compilación. Esto incluye identificar estructuras del tipo (X+)+, (X*)* o combinaciones equivalentes que son conocidas por generar explosión exponencial de estados en implementaciones de DFA.

Ambas medidas deben aplicarse en los dos backends afectados (xgrammar y outlines) de forma independiente, ya que comparten la misma superficie de ataque pero tienen implementaciones distintas.