Un proveedor te manda un ZIP con el proyecto. Lo descomprimes y abres la carpeta con tu agente de IA para echarle un vistazo. Según cuál sea el agente, ya no hace falta nada más: ni aprobar una orden, ni que se llame a ningún modelo, ni que nadie te pregunte si confías en esa carpeta. Y un programa que eligió otra persona se está ejecutando con tus permisos.
Eso no es una hipótesis de laboratorio: es la descripción textual de cuatro CVE publicados entre el 10 de agosto y el 3 de septiembre de 2026 contra productos de tres fabricantes distintos. Y la parte interesante no es el fallo —que se arregla— sino la vía de entrega, porque es la única parte que no depende de ningún fabricante y la que casi todo el mundo está leyendo al revés.
Quien ejecuta el programa no es el agente: es git
La pieza central se llama core.fsmonitor y no es una vulnerabilidad de git: es una opción documentada que hace exactamente lo que dice. La documentación oficial, después de explicar el monitor integrado, remata con una frase que conviene leer despacio: «Otherwise, this variable contains the pathname of the "fsmonitor" hook command». Es decir, el valor de esa variable es la ruta de un programa, y git lo ejecuta para ahorrarse recorrer el árbol de ficheros: «This hook command is used to identify all files that may have changed since the requested date/time».
Ese ajuste vive en el .git/config del propio repositorio. Y git status o git diff refrescan el índice, así que lo invocan. Un agente de IA, al abrir una carpeta, hace justo eso: llama a git para saber en qué rama está, qué ficheros hay tocados y qué contexto meterle al modelo. Ahí se acaba la cadena. No hace falta ninguna astucia más.
Los cuatro expedientes, con sus números
| CVE | Producto | CVSS | Clave abusada | Qué hace falta |
|---|---|---|---|---|
CVE-2026-19592 | Codex CLI / Desktop | 7,3 (v3.1) | core.fsmonitor | Abrir o usar el repo |
CVE-2026-19593 | Codex Desktop | 9,8 (v3.1) | attr.tree + filtro | Abrir el espacio de trabajo |
CVE-2026-72718 | goose (Block) | 7,0 (v4.0) | core.fsmonitor | goose review |
CVE-2026-71963 | Hermes Agent | 8,8 (v3.1) | core.fsmonitor | Mandar un mensaje |
La última columna es la que conviene no saltarse, porque la prensa la ha aplanado: no son cuatro «abres la carpeta y ya». Los dos de Codex sí: basta con abrir el espacio de trabajo. En goose hay que lanzar goose review, y en Hermes hay que mandar un mensaje cualquiera. Lo que comparten los cuatro no es que no hagas nada, es qué es lo que ocurre antes de que nadie pregunte nada.
El de goose es el que más detalle da, hasta el punto de nombrar el fichero fuente: las llamadas vulnerables las construye git_command() en crates/goose-cli/src/commands/review/handler.rs, y las usan touched_files() y collect_diff(). Corregido en la 1.44.0. La frase que importa de su registro es cuándo ocurre: «The command runs before goose contacts a model and without a submitted prompt, model call, tool approval, or trust prompt». En el de Hermes Agent (versiones 0.18.2 a 0.21.0, corregido en el commit f6234d0) el resultado se describe sin eufemismos: el comando inyectado se ejecuta en el contexto del proceso del usuario «exposing the full environment including configured provider API keys».
La variante que no se ve en tu carpeta
El CVE de 9,8 merece párrafo aparte porque no usa fsmonitor y es el más incómodo de auditar. Usa attr.tree, otra opción perfectamente documentada: «A reference to a tree in the repository from which to read attributes, instead of the .gitattributes file in the working tree». Léelo otra vez: los atributos no se leen del .gitattributes que tú ves al abrir la carpeta, sino de un objeto tree guardado dentro del repositorio. Combínalo con un filtro clean o process declarado en el .git/config y ya tienes un programa que git ejecuta al refrescar el índice.
Lo incómodo de auditarlo es eso: la regla que asigna el filtro al fichero no está en ningún sitio que un revisor humano mire al recibir un proyecto. Pero del 9,8 conviene decir de dónde sale, porque el expediente tiene truco. Las puntuaciones de los dos CVE de Codex no las pone OpenAI: son métricas secundarias aportadas por el programa ADP de CISA. Y el vector que le asignan, AV:N/AC:L/PR:N/UI:N, dice que no hace falta interacción del usuario, cuando la descripción del mismo CVE exige que el usuario abra el repositorio preparado. Nosotros nos quedamos con la descripción, que es la que firma quien investigó, y ahí los requisitos son dos: «Exploitation requires Git to be available on PATH and the user to open the attacker-prepared repository with its local Git configuration intact». El primero es banal. El segundo es todo este post.
Por eliminación: el clone no es la vía
La reacción natural al leer esto es «pues ya no clono repositorios raros». Y es justo la conclusión equivocada, porque el git clone es el único camino que no funciona. Lo dice el propio registro del CVE, sin dejar hueco a interpretación: «An ordinary Git clone does not preserve the source repository's local .git/config; exploitation requires a repository delivered or copied with that configuration intact».
Clonar es un protocolo: el servidor manda objetos y referencias, y tu git escribe un .git/config nuevo. Copiar es otra cosa: copiar mueve bytes, y entre esos bytes va el .git entero. Así que la pregunta no es por dónde clonas, sino por dónde te llegan carpetas. La nota de la Cloud Security Alliance enumera las vías que sí funcionan —«a .zip archive, a folder on a shared network drive, a synced cloud-storage folder, or a USB stick»— y lo que nos interesa de esa lista es que no describe cuatro escenarios exóticos: describe cuatro cosas que tu empresa ya tiene montadas y pagadas.
- ·El ZIP adjunto al correo del cliente o del proveedor. Tu pasarela mira macros y ejecutables; una carpeta oculta con ficheros de texto le parece un proyecto.
- ·La carpeta del recurso compartido, el NAS donde se deja «lo del proyecto de fulanito» y donde escribe media empresa.
- ·La carpeta sincronizada de almacenamiento en la nube, que además replica el
.gita todos los que la comparten. - ·El pendrive y el contenedor de desarrollo prefabricado que alguien se bajó porque «ya trae el entorno montado».
Ninguna de esas cuatro puertas mira dentro de un .git/config. Ya escribimos sobre el otro extremo del mismo problema cuando aparecieron miles de repositorios falsos cebados para que los recomendara un agente; aquello iba de qué te descargas. Esto va de qué te dejan encima de la mesa.
Git sí tiene una comprobación. Y estas cuatro vías la desarman
Aquí está, para nosotros, lo más interesante de todo el asunto, y no aparece ni en la nota de la Cloud Security Alliance ni en la divulgación original. Git no es ingenuo con esto. Desde el lío de safe.directory lleva una defensa dura y su documentación la describe así: «By default, Git will refuse to even parse a Git config of a repository owned by someone else, let alone run its hooks». Ni siquiera lee la configuración. Es exactamente la protección que haría falta.
Ahora vuelve a mirar cómo llega la carpeta. En el camino normal —descomprimes el ZIP, te copias del recurso compartido a tu disco, el cliente de sincronización la escribe— el último que escribe los ficheros eres tú, y salen a tu nombre. La comprobación pasa sin despeinarse. Porque esa defensa está diseñada contra el repositorio de otro en tu disco, y lo que tienes delante es tu copia del repositorio de otro. Son cosas distintas y se comportan igual de mal.
El matiz, porque lo tiene y no queremos venderlo más redondo de lo que es: no vale para todos los casos. Si abres el repositorio en el sitio, sobre un recurso de red que conserva el identificador de usuario de quien lo dejó ahí, git sí salta con su aviso de propiedad dudosa y se niega a leer la configuración. Lo mismo si alguien montó el pendrive como root sin reasignar propietario. El problema es que ninguno de esos dos es el gesto habitual: el gesto habitual es traérselo a mi disco y abrirlo, y ese es justo el que desactiva la defensa.
Y hay un segundo detalle en la misma documentación que cierra el razonamiento. Git tiene un concepto llamado configuración protegida, pensado exactamente para esto: «Protected configuration refers to the system, global, and command scopes. For security reasons, certain options are only respected when they are specified in protected configuration, and ignored otherwise». Hay opciones que un repositorio simplemente no puede fijar. safe.bareRepository es una de ellas, y la documentación lo justifica con todas las letras: «This prevents untrusted repositories from tampering with this value». ¿Cuántas opciones hay en ese club? Lo hemos contado: de los 97 ficheros de Documentation/config/ de la rama principal de git, solo tres opciones se documentan como respetadas únicamente en configuración protegida —safe.directory, safe.bareRepository y uploadpack.packObjectsHook—. Tres, en todo git. core.fsmonitor, una opción cuyo valor documentado es la ruta de un programa, no es una de ellas.
El contraargumento es bueno y hay que ponerlo: core.fsmonitor es por naturaleza un ajuste por repositorio —existe para acelerar árboles enormes, y cada árbol es distinto— y meterlo en configuración protegida lo dejaría casi inservible. Por eso tanto la nota de la CSA como la divulgación original ponen el arreglo donde toca: que sea el agente el que llame a git con -c core.fsmonitor=false. De acuerdo. Lo que no se sostiene es la coda tranquilizadora de que esto es «un fallo de los agentes de IA» y ya está: el ajuste que ejecuta programas lo lee git, de un fichero que venía dentro del ZIP, y los agentes solo fueron los primeros en llamar a git lo bastante rápido como para que se notara.
El control existía. Corría en segundo lugar
Los cuatro registros, con independencia de lo que haya que hacer para disparar cada uno, describen la misma coreografía con palabras parecidas. En el de Codex de 9,8: el programa corre «without a workspace-trust prompt, command approval, or interaction with a model». En el de 7,3: «outside Codex's command sandbox and without a user-approval prompt». En el de goose, ya citado, antes de cualquier prompt, modelo, aprobación de herramienta o diálogo de confianza. Y en Hermes, aunque haga falta mandar un mensaje, lo que ejecuta el comando no es el modelo contestando: es el refresco del índice que el agente lanza para preparar la respuesta.
Lo que llama la atención no es que faltara el control: es que estaba. Los cuatro productos tienen su diálogo de «¿confías en esta carpeta?» y su sandbox de órdenes. Y los cuatro recogían contexto con git antes de preguntar, porque preguntar sin saber qué hay delante queda feo. Un control que se ejecuta después de lo que pretende controlar no es un control: es documentación. Esto no va de agentes de IA, va del orden de las operaciones, y es el mismo error que convierte un diálogo de elevación en un adorno cuando el instalador ya copió el fichero.
«Actualiza el agente» no es una respuesta cuando no hay parche
Los cuatro CVE son parte de un conjunto mayor. Según la nota de investigación que publicó la Cloud Security Alliance el 4 de septiembre de 2026 sobre la divulgación de Manifold Security, son ocho hallazgos en siete agentes, comunicados a los fabricantes entre el 26 de junio y el 20 de julio de 2026. Claude Code aparece como vulnerable en la 2.1.193 y corregido en la 2.1.196; Cursor, también corregido, cerrado como duplicado de un informe interno. Y, según esa misma nota, cuatro de los ocho caminos seguían sin parche el día de la publicación, con Qwen Code confirmado vulnerable en 0.19.6 y 0.22.3 y Grok Build en 0.2.93 y 1.0.13.
Esa cifra —la mitad sin corregir— es la que convierte un boletín en una pregunta de gestión. Si el remedio fuera «actualiza», bastaría con tu herramienta de parcheo. Como la mitad no tiene a dónde actualizar, lo único que sirve es saber qué agentes hay instalados, en qué versión y en qué portátiles. Y esa lista, cuando nos sentamos a pedirla, casi nunca existe: los agentes entraron uno a uno, instalados por la persona que los iba a usar, con su propia clave de proveedor y sin pasar por nadie.
Qué mirar el lunes, sin esperar a nadie
Leer la configuración no ejecuta nada; lo que ejecuta es git status y git diff. Así que, en una carpeta que no haya llegado por clone, esto se puede hacer antes de abrirla con ninguna herramienta:
git -C /ruta/al/repo config --local --includes --list \
| grep -Ei 'fsmonitor|hookspath|sshcommand|credential\.helper|^filter\.|^attr\.tree|
textconv|\.driver=|^alias\.|^include|pager|external'
El --includes no es decorativo, y es la parte de este post que más nos costó ver. Si lo omites, tu grep miente. La documentación de git config dice que esa opción «Defaults to off when a specific file is given (e.g., using --file, --global, etc) and on when searching all config files», y --local es un ámbito concreto: por defecto, no sigue las directivas include. Basta con que el .git/config recibido tenga un [include] path = otro-fichero y meta ahí el fsmonitor para que tu comprobación salga limpia y git status ejecute el programa igualmente.
Si sale cualquier cosa, no la negocies: la configuración recibida se aparta entera y se escribe una nueva. Y si tienes que mirar el estado de un repositorio del que dudas, la opción -c de la línea de órdenes gana a la configuración del repositorio. Lo dice el manual de git sin rodeos: «Pass a configuration parameter to the command. The value given will override values from configuration files».
mv /ruta/al/repo/.git/config /ruta/al/repo/.git/config.recibido git -C /ruta/al/repo -c core.fsmonitor= status
Honestidad por delante, porque esto es lo que separa un consejo de un placebo: la segunda línea es un apaño por clave, no una frontera. Neutraliza core.fsmonitor y no te protege de attr.tree ni de la siguiente clave que alguien encuentre, y el grep de arriba tampoco es una lista cerrada —la propia nota de la CSA señala además core.hooksPath, credential.helper y las herramientas externas de diff y merge—. La frontera de verdad es la primera línea de la caja: si la carpeta no llegó por clone, su .git es contenido de un tercero y se trata como tal. Lo demás es ir tapando agujeros de uno en uno.
Un agente es un sistema de producción, no una extensión
En everyWAN tenemos automatización propia con n8n autoalojado haciendo tareas internas en producción, y la tratamos como lo que es: inventariada, con dueño y con ventana de actualización. No porque seamos especialmente disciplinados, sino porque cuando una pieza así se cae o se tuerce, no se nota en una pantalla: se nota en lo que deja de pasar. Un agente de código en el portátil de un desarrollador es la misma categoría de cosa, con un agravante: corre con la sesión de una persona que tiene claves de nube, acceso al repositorio de la empresa y permiso para hacer push. De qué nombre acaba en el registro de auditoría cuando un agente usa el token de alguien ya escribimos en su día; este caso es el escalón anterior, cuando el agente ni siquiera ha empezado a trabajar.
Y el conflicto de interés por delante: everyWAN vive de la consultoría y de los servicios gestionados, y poner orden en esto se factura. La parte comprobable de este post es la que va entre comillas y enlazada al final; el grep de arriba lo puede pasar cualquiera esta mañana sin nosotros, y es exactamente lo que recomendamos hacer antes de pedirle presupuesto a nadie, nosotros incluidos.
Fuentes (verificadas el 5 de octubre de 2026): las descripciones, fechas de publicación, puntuaciones CVSS, vectores, versiones afectadas y corregidas y las frases citadas de los cuatro expedientes — NVD: CVE-2026-19592 y CVE-2026-19593 (ambos publicados el 1 de septiembre de 2026, CWE-15), CVE-2026-72718 (10 de agosto de 2026, CWE-94, corregido en goose 1.44.0) y CVE-2026-71963 (3 de septiembre de 2026, CWE-78). Las definiciones de core.fsmonitor y attr.tree, el apartado de configuración protegida, la frase sobre la negativa a leer la configuración de un repositorio ajeno y la regla de precedencia entre ficheros — documentación oficial de git-config. El recuento de ocho hallazgos en siete agentes, el calendario de notificación a fabricantes, las versiones de Claude Code, Cursor, Qwen Code y Grok Build, el dato de los cuatro caminos sin parche y la enumeración citada de las vías de entrega — nota de investigación de la Cloud Security Alliance del 4 de septiembre de 2026 sobre la divulgación de Manifold Security. La frase sobre la opción -c — manual de git. El recuento de tres opciones con configuración protegida es nuestro, hecho sobre los 97 ficheros de Documentation/config/ de la rama principal del repositorio de git. Fotografía de portada: «External hard drive connected laptop», de Markus Spiske, vía rawpixel y Openverse, dominio público (CC0).
¿Qué agentes de IA hay instalados en tu empresa, y en qué versión?
No cuántas licencias: qué corre en cada puesto, con qué clave y con acceso a qué. Montamos el inventario de la capa de automatización e IA, le ponemos dueño y ventana de actualización, y dejamos escrito qué puede tocar cada agente bajo criterio Zero Trust, incluidas las carpetas que llegan de fuera.
Hablar con everyWAN