sistema: OPERATIVO
← volver a todos los hacks
SUPPLY CHAIN MEDIUM NEW

Los archivos GGUF son entrada no confiable: las RCE recurrentes del parser de llama.cpp

CVE-2026-33298 (marzo de 2026) y una divulgación en oss-sec del 15 de mayo de 2026 muestran que el parser GGUF de llama.cpp encadena corrupciones de heap por desbordamiento de enteros: cargar un modelo manipulado puede bastar para ejecutar código.

2026-06-05 // 6 min affects: llama.cpp, ggml, gguf, ollama, lm-studio

En resumen El formato de archivo que hace funcionar los LLM en local — GGUF — lo analiza código C/C++ sin garantías de memoria en llama.cpp y su núcleo ggml. CVE-2026-33298, publicada el 18 de marzo de 2026 (CVSS 7.8), es un desbordamiento de enteros en el cálculo del tamaño de los tensores: un archivo de modelo manipulado puede corromper el heap y, potencialmente, ejecutar código. No es la primera: CVE-2025-53630 (julio de 2025) era de la misma clase, y un aviso de divulgación completa fechado el 15 de mayo de 2026 enumera seis debilidades más del parser GGUF. La lección es estructural: un archivo de modelo es entrada no confiable, y el cargador es una superficie de ataque.

¿Qué es esto?

GGUF es el formato contenedor de facto para los grandes modelos de lenguaje ejecutados en local. Cuando descarga un modelo cuantizado de Hugging Face y lo ejecuta con llama.cpp, Ollama, LM Studio o cualquier herramienta construida sobre la biblioteca ggml, ese archivo .gguf lo analiza código C/C++ en su máquina antes de cualquier inferencia.

CVE-2026-33298, divulgada en el aviso de seguridad de GitHub GHSA-96jg-mvhq-q7q7 el 18 de marzo de 2026 (CWE-122 / CWE-190, CVSS 7.8, AV:L/AC:L/PR:N/UI:R), es un desbordamiento de enteros en la función ggml_nbytes — la rutina que calcula cuántos bytes necesita un tensor. Un archivo con dimensiones de tensor fabricadas hace que ese cálculo «se dé la vuelta», y el parser reserva un búfer mucho menor que el tamaño real del tensor. Lo que parece un fallo aritmético se convierte en corrupción de memoria.

La verdadera historia es la recurrencia. La misma clase de desbordamiento afectó a gguf_init_from_file_impl un año antes con CVE-2025-53630 (publicada el 10 de julio de 2025), y el 15 de mayo de 2026 un investigador independiente publicó un aviso de divulgación completa en oss-sec que describe seis debilidades adicionales en gguf.cpp y en la referencia Python gguf_reader.py — desde la falta de un límite superior en el valor de alineación hasta campos de enumeración y de longitud de cadena sin validar.

Cómo funciona

El patrón es el mismo en todos estos fallos. Un tamaño o un desplazamiento se calcula a partir de valores leídos directamente del archivo controlado por el atacante. En un host de 64 bits, multiplicar dimensiones de tensor grandes desborda size_t, que vuelve a un número pequeño; el cargador confía entonces en ese número pequeño para dimensionar una reserva en el heap. Cuando el código copia o indexa después el tensor a su extensión real (mucho mayor) — o sigue un offset de tensor que apunta más allá del búfer infradimensionado — lee o escribe fuera de la reserva. Esa escritura fuera de límites en el heap es la primitiva sobre la que un atacante construye para corromper estructuras adyacentes y, en el peor caso, desviar la ejecución.

El vector CVSS importa para la priorización: el ataque es local y requiere interacción del usuario (UI:R). Nadie alcanza su proceso de forma remota: el disparador es usted cargando el archivo. Pero en el mundo de los LLM locales, descargar la cuantización GGUF de un desconocido y cargarla es un gesto cotidiano, a menudo automatizado con un simple pull. El archivo se trata como un dato inerte; el parser, en cambio, toma sus campos al pie de la letra.

Por qué importa

ggml y llama.cpp están por debajo de una gran parte del ecosistema de la IA local — Ollama, LM Studio, GPT4All y muchas otras herramientas incorporan el mismo código de análisis. Una debilidad en el análisis de GGUF no es, por tanto, el fallo de un producto, sino el de una dependencia compartida, heredada por todo lo que viene aguas abajo. Y como los hubs de modelos comunitarios hacen trivial publicar y compartir archivos GGUF, el canal de distribución de un modelo malicioso ya está montado y goza de amplia confianza entre los usuarios.

Esto refleja la vieja lección de los checkpoints de Python basados en pickle: los artefactos de modelo están próximos al código, no son datos pasivos. Los esfuerzos de formato «seguro por construcción» (como evitar pickle) responden al problema de la deserialización de código, pero no hacen que el propio parser binario sea seguro en memoria. CVE-2026-33298 y sus parientes muestran que incluso un formato «solo de datos» se vuelve peligroso cuando su parser cuenta mal los bytes.

Defensas

  1. Actualice. CVE-2026-33298 está corregida en la build de llama.cpp b7824. Si distribuye o incrusta ggml/llama.cpp, parta de una versión reciente y siga sus avisos de seguridad — esta clase se repite, así que mejor fijar versión y vigilar que corregir una sola vez.
  2. Trate GGUF como no confiable. Cargue modelos solo de editores en los que confíe; verifique sumas de comprobación y procedencia antes de cargar. La cuantización comunitaria de un autor desconocido merece la misma desconfianza que un binario sin firmar.
  3. Aísle el cargador. Ejecute la carga del modelo y la inferencia en un contenedor mínimo, sin acceso a secretos ni a almacenes de datos sensibles y con tráfico saliente restringido. Aplique límites de memoria y CPU para que un desbordamiento o un agotamiento de memoria degrade a un cierre, no a un pivote.
  4. Valide antes de cargar cuando pueda. Prefiera cargadores mantenidos que comprueben los límites de los tamaños de tensor, los desplazamientos, la alineación y las longitudes de cadena frente al tamaño real del archivo. Si construye herramientas sobre ggml, haga fuzzing del camino GGUF y use aritmética verificada (p. ej. __builtin_mul_overflow) en cada cálculo de tamaño.
  5. Monitorice. Segfaults, abortos del sanitizer o picos de memoria inesperados durante la carga de un modelo son una señal de caza útil: un archivo quizá intentó romper el parser en lugar de ser servido por él.

Estado

ElementoReferenciaFechaNotas
CVE-2026-33298GHSA-96jg-mvhq-q7q72026-03-18Desbordamiento de enteros en ggml_nbytes, desbordamiento de heap, CVSS 7.8, corregido en b7824
Aviso GGUF oss-secseclists.org (V-01…V-06)2026-05-15Seis debilidades más del parser gguf.cpp / gguf_reader.py, divulgación completa
CVE-2025-53630GHSA-vgg9-87g3-85w82025-07-10Misma clase de desbordamiento en gguf_init_from_file_impl, lectura/escritura fuera de límites

El encuadre correcto no es «parchear un CVE». Es que el análisis de GGUF en ggml/llama.cpp ha producido repetidamente la misma clase «desbordamiento de enteros → corrupción de heap» — de modo que cualquier pila que cargue archivos de modelo desde fuera de su frontera de confianza debería añadir controles de procedencia y aislamiento que no dependan de que el parser calcule cada tamaño correctamente.

Sources