Fallo en Claude Code: una issue de GitHub llega a los secretos de CI

10.08.2026 8 min 4

Una issue de GitHub abierta por alguien sin ningún permiso sobre el repositorio bastó para llegar a los secretos de su cadena de compilación. Novee Security lo mostró en Black Hat USA el 5 de agosto de 2026, sobre tres agentes de código con IA a la vez: Claude Code de Anthropic, Gemini CLI de Google y Codex de OpenAI. Ninguno de los ataques rompió un modelo. Rompieron el arnés que lo rodea, el código corriente que decide qué órdenes puede ejecutar el modelo.

Cómo una issue de GitHub llega a los secretos de CI

Los tres agentes se conectan a la integración continua igual. Un evento del repositorio, una issue o un pull request, dispara un workflow, el workflow arranca el agente en un runner, y el agente lee el texto del evento como parte de su tarea. Ese texto lo escribe quien abrió la issue. En un repositorio público, cualquiera.

La inyección de prompt por esa vía es un problema conocido, y cada una de estas herramientas tiene una capa de validación que debería contenerla. La investigación va de que esa capa falla, no de que el modelo sea crédulo. Un runner guarda las credenciales que la cadena necesita: tokens del repositorio, claves de nube, las propias claves de API del agente. Quien ejecuta una orden en el runner alcanza todo eso.

El fallo de Claude Code: un desacuerdo de comillas y un contador de descargas

La cadena contra Claude Code empezó con un desacuerdo sobre las comillas. El validador de órdenes quitaba el texto entre comillas simples antes de aplicar sus veintitrés comprobaciones de seguridad, dando por hecho que un shell trataría ese contenido como datos inertes. Después el arnés pasaba la orden ya sin esas comillas. Un valor colado en el indicador --receive-pack de git parecía por tanto inofensivo en la validación y se ejecutaba en el runner.

Lo que vino después es lo interesante. Anthropic publicó un parche y los investigadores encontraron una segunda vía con tac, una orden de solo lectura que invierte el contenido de un archivo, para imprimir una clave de API al revés en un registro público de compilación. También se corrigió. La tercera ronda, registrada como CVE-2026-54316, renunció a imprimir nada: la clave se filtró carácter a carácter mediante el contador público de descargas de un modelo en Hugging Face, leyendo la respuesta desde fuera. La puntuación es 9,1 en CVSS v3.1 y 6,0 en CVSS v4; Anthropic la clasifica como moderada porque un atacante debe antes meter contenido no fiable en el contexto del agente. Afecta a las versiones desde la 0.2.54; la corrección llegó en la 2.1.163, con el aviso GHSA-fg94-h982-f3mm.

Importante: un canal encubierto no necesita ancho de banda. Una clave que se escapa a un carácter por petición mediante un contador público no aparece en ningún registro, porque nunca salió nada con una forma que mereciera revisarse. El filtrado de salida no lo ve, y un proxy tampoco.

Gemini CLI: la peor nota de las tres

La herramienta de Google se llevó lo más duro. CVE-2026-12537 tiene una puntuación CVSS de 10,0: el lanzador de contenedores analizaba su lista blanca de herramientas una sola vez, al registrarlas, y no comprobaba nada en tiempo de ejecución. Con el indicador --yolo, cualquier orden pedida por el modelo se aprobaba automáticamente, y una inyección de órdenes del sistema mediante un archivo .gemini/.env preparado ejecutaba código en el host de CI antes incluso de que arrancara el sandbox. Son vulnerables todas las versiones hasta la 0.39.0 inclusive; la corrección está en la 0.39.1, con la acción de GitHub actualizada a run-gemini-cli 0.1.22 y el aviso GHSA-wpqr-6v78-jr5g.

Con Codex salió distinto. Dos pasadas de Codex compartían un mismo checkout dentro de un solo job, así que la primera podía escribir un archivo AGENTS.md que la segunda cargaba luego como instrucciones. La postura de OpenAI es que el sandbox se comportó tal y como está documentado, de modo que no se publicó parche de versión. Lo que cambió fueron las recomendaciones de workflow: separar las pasadas en jobs distintos y declarar explícitamente los archivos de instrucciones del repositorio como parte de la superficie de entrada no fiable.

Por qué el acceso robado sigue funcionando

Una investigación aparte de Silverfort, publicada el 28 de julio de 2026, explica por qué un solo robo vale tanto. En macOS, Claude Code CLI escribe su paquete OAuth en el llavero como contraseña genérica, bajo el nombre de servicio "Claude Code-credentials", creada mediante /usr/bin/security sin argumentos de control de acceso. La entrada hereda la lista de acceso por defecto, que confía en la herramienta que la creó. Como esa herramienta es un binario de Apple de uso general que cualquier proceso puede invocar, una sola línea de órdenes devuelve el paquete entero, sin Touch ID y sin contraseña.

El paquete contiene un token de acceso de vida corta y un token de refresco de vida larga, además de credenciales de los servidores MCP conectados. El problema es el token de refresco: puede canjearse por nuevos tokens de acceso hasta que alguien lo revoque, y no está ligado ni a un dispositivo ni a una dirección. Anthropic no lo considera una vulnerabilidad, con el argumento de que los procesos del mismo usuario ya son de confianza, aunque dice estar siguiendo un endurecimiento del control de acceso como mejora de defensa en profundidad. Conviene señalar que su propia aplicación de escritorio lo hace al revés: allí los tokens se guardan cifrados con una clave ligada a la firma de código, y cualquier intento ajeno de acceder a ella provoca una petición de contraseña.

Qué hacer si usa estos agentes

  • Actualizar primero: Claude Code 2.1.163 o posterior, Gemini CLI 0.39.1 junto con run-gemini-cli 0.1.22. Para Codex no hay nada que instalar, solo un workflow que cambiar.
  • No dejar que eventos públicos lancen un agente: un workflow que arranca con cualquier issue o pull request desde cualquier cuenta entrega la superficie de entrada a desconocidos. Exija una etiqueta, el comentario de un responsable o una comprobación de fork.
  • Recortar los secretos del runner: dé al job el token más estrecho con el que pueda trabajar y mantenga las claves de nube de larga vida fuera de los workflows que un agente pueda tocar.
  • Separar las pasadas: si dos ejecuciones del agente comparten un checkout, la primera puede escribir las instrucciones que obedecerá la segunda. Jobs distintos, checkouts distintos.
  • Rotar por sospecha, no por prueba: cerrar sesión, volver a entrar y luego renovar las claves en consola. Limpiar la máquina no invalida un token de refresco que ya salió.
  • Vigilar la misma sesión en dos máquinas: la reutilización de credenciales desde equipos distintos es justo la señal que estos tokens hacen posible, porque nada los ata al dispositivo.

Por qué importa más allá de los desarrolladores

El patrón se repite conforme los agentes ganan autonomía: el ataque no llega por la red como tráfico inspeccionable, llega como contenido y se ejecuta dentro de una sesión que ya es de confianza. Escribimos sobre la misma forma cuando un navegador con IA podía ser secuestrado por una publicación que el usuario nunca pulsó, y por eso mismo resulta peligrosa una cadena como el fallo del formulario de acceso de WordPress que acaba en código en el servidor, aunque necesite que un administrador simplemente abra una página. Aquí está también el límite honesto de las herramientas de privacidad de red. Una VPN oculta su tráfico a la red en la que está y mueve su ubicación aparente; no tiene visión de lo que su propio agente decide ejecutar, ni se interpone entre un proceso y el llavero del mismo portátil. El cifrado en tránsito nunca fue la frontera que cruzan estos ataques.

Conclusión

Conclusión: tres proveedores, tres fallos distintos, una forma común. Al modelo no lo engañaron con nada que no hubiera engañado también a una persona atenta; falló el código que rodea al modelo, el que prometía poner límites. Como lo formuló uno de los investigadores, el arnés es el código entre el modelo y el mundo real. Ninguno de los fallos figura como explotado en el mundo real y los parches existen, así que la reacción útil hoy es poco vistosa: actualizar los agentes, dejar de permitir que eventos anónimos del repositorio los arranquen y tratar cada credencial que hayan tocado como algo que hay que rotar, no limpiar.

claude codeanthropicgemini cligoogleopenaicodexgithubhugging facenovee securitysilverfortblack hatcve-2026-54316cve-2026-12537prompt injectionai agentmacosapplekeychaincybersecuritysecurityprivacyvpn

Lee también