Volver a todas las publicaciones
Publicado el · por Renaud Deraison

Tres agentes, una sola cosa que robar

En Black Hat USA 2026, Novee rompió la configuración por defecto de Claude Code, Gemini CLI y Codex de tres maneras distintas, cada una partiendo de una issue de GitHub que un desconocido anónimo podía abrir. Los rodeos no guardaban relación — un desajuste de comillas, una allowlist de shell sin aplicar, un AGENTS.md de confianza — pero las tres cadenas terminaban en el mismo paso: leer una credencial real desde el propio proceso del agente. Bromure Agentic Coding no blinda ese último paso. Vacía el proceso: la exfiltración se ejecuta y entrega un señuelo.

Tres fabricantes, tres bugs de harness sin relación entre sí, un mismo movimiento final: leer la clave de API o el token que está en el proceso del agente y mandarlo fuera. En un perfil Bromure ese valor es un placeholder brm_…. La exfiltración tiene éxito y el atacante recibe una cadena que no significa nada fuera de su Mac.

En Black Hat USA 2026, esta semana, Novee presentó “Trusted Enough to Run: Breaking AI Agents in Official Workflows”. El investigador Elad Meged probó la configuración por defecto de tres agentes de código contra los repositorios públicos de cada fabricante, y rompió los tres. Los artículos aparecieron el 6 de agosto.

El punto de entrada fue el mismo en todos los casos, y es el más barato que existe: una issue o pull request de GitHub abierta por un desconocido anónimo sin ningún privilegio. El agente lee ese texto no confiable como parte de su trabajo, y el harness — el código alrededor del modelo que decide qué puede ejecutar — no consigue mantener ese texto al otro lado de la línea. Novee encontró los mismos valores por defecto vulnerables en más de cien repositorios públicos más allá de los tres fabricantes probados.

Los tres caminos de ataque no tienen nada que ver entre sí. Terminan en el mismo sitio, y ese final compartido es la parte que conviene llevarse a casa.

Tres puertas distintas, una misma pared del fondo

Claude Code

La cadena registrada como CVE-2026-54316 usó dos costuras. La primera era un desajuste entre cómo Claude Code validaba un comando y cómo el shell lo interpretaba en realidad: una cadena entre comillas que al validador le parecía inocua se parseaba de otro modo una vez en manos de bash, y una bandera git push --receive-pack atravesó veintitrés comprobaciones de seguridad que estaban todas, individualmente, haciendo su trabajo. La segunda costura era la exfiltración. Un tac de solo lectura — el comando que imprime un archivo al revés — bastaba para leer un secreto y sacarlo invertido por los logs de GitHub Actions, y una variante filtraba la clave de API carácter a carácter empujando el contador público de descargas de un modelo de HuggingFace y leyéndolo de vuelta. Anthropic publicó correcciones.

Gemini CLI

Calificado con CVSS 10.0. En modo headless, Gemini CLI confiaba automáticamente en la carpeta de trabajo y cargaba cualquier configuración de agente que encontrara allí — sin sandbox, sin aprobación — de modo que una pull request que plantara un archivo de configuración se ejecutaba antes de que la sandbox llegara a inicializarse. Dos supuestos del harness cedieron: la allowlist de shell “restringida” nunca se aplicaba en tiempo de ejecución, y el saneamiento de entorno que limpiaba los secretos del proceso hijo los dejaba en el proceso padre, legibles a través de /proc. Google publicó un cambio de ruptura en el modelo de confianza headless en 0.39.1 y 0.40.0-preview.3.

Codex

Codex ejecuta dos pasadas de agente sobre un espacio de trabajo compartido. .git y .codex estaban protegidos contra escritura; AGENTS.md no, y se recargaba como instrucciones de confianza en cada ejecución. La primera pasada, al procesar entrada no confiable, escribía un AGENTS.md envenenado; la segunda, la “segura”, lo cargaba como autoridad y llevaba las instrucciones maliciosas adelante con permisos elevados. OpenAI separó las pasadas en jobs aislados en tres días.

Puertas distintas, misma pared del fondoClaude Code · CVE-2026-54316validador y shell parsean lacadena de forma distintagit push --receive-pack pasa 23 controlestac lo lee; los logs de Actions lo sacancontador HuggingFace filtra char a charGemini CLI · CVSS 10.0el modo headless confía en la carpetala config corre antes de la sandboxallowlist restringida nunca aplicadahijo limpio, pero secretos del padreaún legibles vía /procCodex · AGENTS.mddos pasadas, un mismo workspace.git y .codex protegidos; AGENTS.md nola pasada 1 envenena el archivola pasada 2 segura lo lee como autoridady lo lleva adelante, elevadaEl último paso compartidoleer una credencial real del procesoo del entorno, y mandarla fuera
Tres rodeos de harness sin relación, divulgados juntos. Las puertas difieren — un desajuste de comillas, una allowlist sin aplicar más una fuga por /proc, un archivo de instrucciones de confianza que sobrevive entre pasadas. La pared del fondo es idéntica: cada cadena termina leyendo una credencial real del proceso o del entorno del agente y enviándola a alguna parte.

La parte que es igual

El propio resumen de Novee es que “ninguna de estas era una simple mala configuración: eran decisiones de seguridad correctas que se venían abajo en los puntos de traspaso”. Esa es la lectura correcta sobre el harness. Pero mire dónde termina cada cadena.

El tac de Claude lee una credencial y el contador de HuggingFace filtra la clave de API. El hueco de /proc de Gemini expone los secretos del proceso padre. La segunda pasada elevada de Codex lleva los tokens del entorno a una instrucción controlada por el atacante. Tres costuras sin relación se abren de tres maneras distintas, y cada una termina alargando la mano hacia el mismo objeto: un secreto real que estaba en el proceso o en el entorno del agente, esperando a que lo leyeran.

Ese es el supuesto que comparten todos estos exploits: que si consigues ejecutar código como el agente, la credencial está ahí mismo. Y casi siempre lo está. La ANTHROPIC_API_KEY, el GITHUB_TOKEN, las claves de AWS: la manera corriente de ejecutar un agente de código las pone todas en el entorno del proceso, porque es ahí donde las herramientas esperan encontrarlas.

Bromure Agentic Coding no intenta ganar la carrera armamentística del harness. Retira lo que el harness está protegiendo.

Dónde se rompe la cadena

Bromure ejecuta el agente de cada perfil dentro de una VM Linux desechable en Apple Silicon, y encamina cada byte de su tráfico de red por un proxy en el host, fuera de la caja en la que corre el agente. Puede ejecutar el mismo agente autónomo de triaje de issues que Novee atacó — alojándolo usted mismo en lugar de entregarle un runner de workflow. Recorra las tres cadenas contra esa disposición y cada una se deshace, y el paso de la credencial se deshace de la misma manera en las tres.

La credencial nunca está en el proceso

Esta es la garantía que neutraliza el último paso compartido. Las claves reales de Anthropic, OpenAI y xAI se inyectan en la VM como placeholders brm_… y se cambian por los valores reales solo en el proxy del host, en el cable, para el único host de destino al que pertenece cada una. La clave nunca está en la memoria de la VM, nunca en /proc, nunca en una variable de entorno que un proceso hijo o padre pueda leer, nunca en un log. tac lee un señuelo. El contador de HuggingFace filtra un señuelo carácter a carácter. El raspado de /proc devuelve un señuelo. Cada exfiltración de la charla se ejecuta hasta el final y envía una cadena que solo se resuelve en exactamente un Mac, que no es la máquina en la que corrió.

El RCE aterriza en una caja que puede borrar

“Ejecución de código en el host que ejecuta el agente” es la frase del aviso de Gemini, y ese host es la frontera de confianza que Bromure mueve. La ejecución pre-sandbox de Gemini y el bypass de shell de Claude reciben ambos una VM Linux desechable, a un hipervisor de macOS, en NAT, desde la que nada de su red es alcanzable. Erase home descarta lo que la ejecución escribió y devuelve el directorio home a su estado posterior al clone. El exploit que se adueña del agente se adueña de una VM que usted iba a tirar de todos modos.

La escritura en main se rechaza en el proxy

Las dos escaladas apuntan al mismo premio: la cadena de Claude empuja con git push --receive-pack, la de Gemini empuja código malicioso a la rama principal. Esa es la mitad de cadena de suministro — un checkout comprometido se convierte en un paquete envenenado aguas abajo. Ponga la barrera de GitHub en solo lectura o en bloqueo de acciones destructivas y git-receive-pack se rechaza en el proxy del host, donde una guardia burlada dentro de la VM no tiene voto. Los fetch siguen pasando; el push que envenenaría la rama, no.

El archivo de instrucciones se puntúa antes de obedecerse

La entrada es texto no confiable de issues y PR que el harness no supo contener, y toda la cadena de Codex vive en un AGENTS.md escrito. Bromure puntúa el contenido de los resultados de herramienta que el agente lee — páginas web, cuerpos de issues, contenidos de archivos — con un modelo local de inyección de prompts, y puntúa los propios archivos de autoridad (CLAUDE.md, AGENTS.md y sus variantes) con un clasificador dedicado más un escáner de payloads de Unicode invisible. El AGENTS.md envenenado entre las dos pasadas de Codex es exactamente lo que ese segundo detector está construido para atrapar, y corre en el host antes de que el modelo actúe sobre el archivo.

Dos de esos ajustes vienen activados por defecto, y el broker de credenciales no es un ajuste en absoluto: es la manera en que un perfil Bromure guarda un secreto, sin más. Los canales encubiertos completan el cuadro: el log de GitHub Actions, el contador de HuggingFace, el host saliente inesperado cruzan todos el proxy del host, y el Security Log y el Trace Inspector registran el host, el estado y el informe de sustitución de cada petición — el canal lateral que filtró un señuelo es también una fila en una lista que usted puede leer.

Una estación de trabajo normalel proceso guardaclave de API, token y creds realesen env vars, /proc y en discoel exploit la leetac, /proc o una pasada elevadala exfiltración entrega una clave realy puede escribirgit push llega a la ramaun paquete envenenado sigue aguas abajoDentro de un perfil Bromureel proceso guardaplaceholders brm_, canjeados en el proxyel valor real nunca entra en la VMel exploit la leemismo tac, mismo /proc, misma pasadala exfiltración entrega un señueloy la escritura se rechazagit-receive-pack bloqueado en el proxyla VM en la que corrió es desechable
El último paso compartido, en dos lugares. En una estación de trabajo normal, el exploit lee una credencial viva directamente del proceso y la exfiltración entrega una clave real. En un perfil Bromure, la misma lectura tiene éxito contra un placeholder, la escritura que envenenaría la rama se rechaza en el proxy, y la caja en la que corrió el agente es desechable.

El harness seguirá rompiéndose

Las tres correcciones que Novee provocó son todas buenas, y todas estrechas. Anthropic corrigió el desajuste de comillas; Google cambió el modelo de confianza headless; OpenAI separó las pasadas. Cada una cierra la costura concreta que se encontró. Ninguna cambia lo que los tres exploits tenían en común: una credencial operativa estaba en el proceso del agente, lista para llevarse. El próximo bug de harness — y Novee encontró los mismos valores por defecto en otro centenar de repositorios, así que habrá un próximo — volverá a alargar la mano hacia ella.

Puede responder a cada divulgación con un parche y una revisión de configuración, y debería. Pero el parche cierra una puerta en un agente, y la revisión es por repositorio y por versión. La credencial que un exploit operativo va a buscar es la misma en los tres agentes y en cada bug futuro, y es lo único que puede poner fuera de alcance con una sola decisión: guarde el secreto real en el host, dele al agente un placeholder, y deje que el proxy produzca el valor real solo para el host al que va dirigido.

Instale Bromure Agentic Coding, y dele al agente una caja — y una credencial — que esté dispuesto a perder.