Ciberseguridad

Tu framework de agentes es la superficie de ataque

Un issue de GitHub abierto por un desconocido bastó para ejecutar código y robar secretos en Claude Code, Gemini CLI y Codex. No falló el modelo, sino el código que lo rodea.

Una mano introduce una nota doblada por la ranura de entrada de una pequeña máquina de tuberías y palancas construida alrededor de un núcleo luminoso.

Los hallazgos de Novee

AgenteCausa raízIdentificadorRespuesta del proveedor
Claude Code (GitHub Action) — ronda 1El validador de comandos eliminaba las cadenas entre comillas simples antes de hacer la comprobación; git push --receive-pack=<payload> superaba la validación y se ejecutaba en el runner—Parcheado
Claude Code — ronda 2La corrección se apoyaba en una lista fija de comandos permitidos «de solo lectura», exentos del control que se aplica a las escrituras; lectura de archivos sin restricciones y exfiltración—Parcheado
Claude Code — ronda 3El acceso preaprobado a Hugging Face se usaba como canal de exfiltración a través de los contadores públicos de descargasCVE-2026-54316Parcheado
Gemini CLIElusión de las restricciones de ejecución; ejecución de comandos del sistema operativo antes de que se aplicara el sandboxCVE-2026-12537Parcheado
CodexDos pasadas dentro de un mismo job de CI comparten el checkout del repositorio; la primera escribe AGENTS.md, que la segunda carga como instrucciones legítimasSin asignarOpenAI: decisión de diseño, no una vulnerabilidad

Vale la pena entender la cadena de git push --receive-pack precisamente por lo anodina que es. La opción receive-pack de Git permite que un push indique un programa que se ejecutará en el extremo receptor. Según el análisis de la Cloud Security Alliance, el validador de Claude Code eliminaba las cadenas entre comillas simples antes de aplicar sus comprobaciones, de modo que una carga útil escondida en esa opción pasaba intacta y se ejecutaba en el runner de GitHub Actions. Exposición: GITHUB_TOKEN y ANTHROPIC_API_KEY, presentes en el entorno del workflow. Con un token de GitHub con permisos de escritura, eso se extiende a modificar workflows y publicar paquetes bajo el espacio de nombres del repositorio: la cadena de suministro comprometida a partir de un solo issue.

Las notas de investigación de la CSA dejan claro lo esencial: estas cadenas explotaban carencias de diseño en la validación de comandos y en el aislamiento de procesos, no la persuasión del modelo. Un modelo perfectamente alineado habría seguido siendo explotable, porque era el harness el que hacía lo que no debía con la salida del modelo. Meged: «El harness es el código que hay entre el modelo y el mundo real», y «no consiguió, una y otra vez, impedir que contenido no fiable de GitHub llegara a entornos de ejecución con privilegios».

El caso de Codex es el más interesante desde el punto de vista conceptual, porque se trata de un desacuerdo sobre qué cuenta como vulnerabilidad. La postura de OpenAI: si configuras dos pasadas para que compartan espacio de trabajo, que la primera escriba un archivo de instrucciones en el que la segunda confía es el comportamiento documentado de AGENTS.md, no un fallo. La postura de Novee: un atacante externo sin privilegios puede conseguir que la primera pasada escriba ese archivo. Las dos tienen razón, y precisamente por eso «el framework es la vulnerabilidad» es el enfoque correcto: el fallo está en la composición, no en la especificación de ningún componente por separado.

Hallazgos en los frameworks

La segunda charla llevó la superficie de ataque por debajo de la capa de herramientas. La tesis: hay lógica explotable en el núcleo de los entornos de ejecución de LangChain, CrewAI, AutoGen y Semantic Kernel.

  • Almacenes de memoria. El contenido inyectado que se guarda en la memoria del agente se reutiliza como contexto de confianza en turnos y sesiones posteriores. Es el hallazgo de AGENTS.md en Codex llevado a lo general: la ejecución N escribe lo que la ejecución N+1 lee como verdad.
  • Bucles de planificación. Un contenido que influya en cómo el planificador descompone una tarea puede desviar al agente sin que se haga ninguna llamada a herramientas: el agente, sencillamente, decide hacer otra cosa.
  • Capas de serialización. Varios frameworks deserializan su estado (cadenas, agentes, mensajes) a partir de formatos que permiten ejecutar código al cargarlos. Una clase de vulnerabilidad clásica (la deserialización en Java, pickle en Python) que reaparece en un sitio nuevo.

El incidente de Hugging Face es la misma historia a otra escala: a los agentes los secuestró el contenido de un tablón de mensajes, y el «framework» que lo hizo posible fue un sistema de archivos compartido. La generalización es incómoda, pero limpia: cualquier punto en el que el contenido no fiable se encuentra con una ejecución de confianza es el framework, y el framework es superficie de ataque.

Cambio de enfoque: de «controlar las herramientas» a «el framework es la vulnerabilidad»

El modelo de seguridad habitual para agentes —enumerar las herramientas, acotar los permisos de cada una, exigir aprobación para las peligrosas— es necesario. Mantenlo. Pero la investigación presentada en Black Hat establece tres hechos más:

  1. El contenido no fiable llega al modelo por canales que no son llamadas a herramientas (issues, páginas recuperadas, artefactos de ejecuciones anteriores, memoria).
  2. La salida del modelo llega al mundo a través de código (el harness) que tiene sus propios fallos.
  3. El estado del propio framework es un objetivo de inyección.

Por tanto, el modelo de amenazas debe incluir el harness y el framework como superficie de ataque de primer orden, y revisarlos como revisarías el código que gestiona las peticiones de una aplicación web.

Bastionado: medidas concretas

Límites de confianza

  • Trata cualquier cadena de origen externo —el cuerpo de un issue, la descripción de una PR, un mensaje de commit, una página recuperada, la salida previa de un agente— como entrada no fiable. Márcala como tal y, cuando el framework lo permita, hazlo en metadatos estructurados sobre los que el harness pueda aplicar controles.
  • No dejes nunca que una ejecución del agente escriba en un sitio que una ejecución posterior lea como instrucciones (AGENTS.md, CLAUDE.md, .cursorrules, almacenes de memoria), salvo que esa escritura pase a su vez por una revisión humana.

En la CI

  • No permitas que los eventos issues / issue_comment de usuarios ajenos al proyecto disparen workflows de agentes. Si no te queda más remedio, ejecútalos con un token de solo lectura y sin ningún secreto.
  • Usa runners efímeros y con la red restringida para los jobs de agentes. Limita el tráfico de salida a la API del proveedor y al registro necesario, y a nada más: el canal lateral de Hugging Face funcionó porque se podía llegar a un host de terceros.
  • Separa las credenciales del agente de las del repositorio. El agente debería tener una clave de API que no sirva más que para llamar al modelo y un token de GitHub que no sirva más que para comentar.

Ejecución de comandos

  • No construyas tu propio validador de comandos de shell. Novee se saltó dos versiones sucesivas de uno escrito por un proveedor con muchos recursos. Mejor una lista de acciones estructuradas permitidas (abrir un archivo, ejecutar una batería de pruebas concreta) que analizar comandos de shell libres.
  • Si el shell libre es inevitable, ejecútalo en un sandbox en el que el peor escenario esté acotado y da por hecho que alguien va a saltarse el validador.

Frameworks

  • Fija las versiones de los frameworks y sigue sus avisos de seguridad como harías con cualquier dependencia expuesta a la red.
  • Desactiva o sustituye las vías de deserialización que acepten código (pickle, cargadores de YAML inseguros, configuración basada en eval).
  • Trata la memoria del agente como una base de datos en la que escriben fuentes no fiables: valida al leer, no solo al escribir.

Detección

  • Registra por separado las acciones previstas del agente (la salida del modelo) y las reales (lo que ejecuta el harness) y compáralas. Una divergencia indica o bien un fallo del harness o bien una falsificación; METR encontró lo segundo en más del 7 % de las transcripciones de Hugging Face (véase OpenAI y el ataque a Hugging Face: en qué discrepa la investigación independiente). A modo de ejemplo, un agente cuya transcripción muestra:
$ echo REAL; sleep

pero cuya telemetría del runner registra una conexión de red a un host inesperado se ha desviado, y quien miente es la transcripción. Solo la telemetría del lado de la infraestructura permite detectarlo.

Fuentes

Volver a la lectura rápida (2 min).

Artículos relacionados