A supplier sends you a ZIP with the project. You unpack it and open the folder with your AI coding agent to take a look. Depending on the agent, nothing else is required: no command approval, no model call, nobody asking whether you trust that folder. And a program somebody else chose is running with your privileges.
That is not a lab hypothesis: it is the literal description of four CVEs published between 10 August and 3 September 2026 against products from three different vendors. And the interesting part is not the flaw —that gets fixed— but the delivery route, because it is the only part that does not depend on any vendor, and the part almost everybody is reading backwards.
What runs the program is not the agent: it is git
The central piece is called core.fsmonitor and it is not a git vulnerability: it is a documented option doing exactly what it says. The official documentation, having explained the built-in monitor, closes with a sentence worth reading slowly: "Otherwise, this variable contains the pathname of the 'fsmonitor' hook command". The value of that variable is the path of a program, and git runs it to save itself walking the file tree: "This hook command is used to identify all files that may have changed since the requested date/time".
That setting lives in the repository's own .git/config. And git status or git diff refresh the index, so they invoke it. An AI coding agent, on opening a folder, does precisely that: it calls git to learn which branch it is on, which files are modified, and what context to hand the model. That is the whole chain. No further cleverness required.
The four case files, with their numbers
| CVE | Product | CVSS | Key abused | What it takes |
|---|---|---|---|---|
CVE-2026-19592 | Codex CLI / Desktop | 7,3 (v3.1) | core.fsmonitor | Open or use the repo |
CVE-2026-19593 | Codex Desktop | 9,8 (v3.1) | attr.tree + filter | Open the workspace |
CVE-2026-72718 | goose (Block) | 7,0 (v4.0) | core.fsmonitor | goose review |
CVE-2026-71963 | Hermes Agent | 8,8 (v3.1) | core.fsmonitor | Send any message |
The last column is the one not to skip, because the coverage has flattened it: these are not four "you open the folder and that is it". The two Codex ones are: opening the workspace is enough. In goose you have to run goose review, and in Hermes you have to send any message. What all four share is not that you do nothing, it is what happens before anybody asks you anything.
The goose entry is the most detailed, to the point of naming the source file: the vulnerable calls are built by git_command() in crates/goose-cli/src/commands/review/handler.rs, and used by touched_files() and collect_diff(). Fixed in 1.44.0. The sentence that matters in that record is the timing: "The command runs before goose contacts a model and without a submitted prompt, model call, tool approval, or trust prompt". In the Hermes Agent one (versions 0.18.2 to 0.21.0, fixed in commit f6234d0) the outcome is described without euphemism: the injected command runs in the user's process context, "exposing the full environment including configured provider API keys".
The variant you cannot see in your folder
The 9.8 CVE deserves its own paragraph because it does not use fsmonitor and it is the most awkward to audit. It uses attr.tree, another perfectly documented option: "A reference to a tree in the repository from which to read attributes, instead of the .gitattributes file in the working tree". Read that again: the attributes are not read from the .gitattributes you can see when you open the folder, but from a tree object stored inside the repository. Combine it with a clean or process filter declared in .git/config and you have a program git runs when it refreshes the index.
That is what makes it awkward to audit: the rule assigning the filter to the file is nowhere a human reviewer would look when receiving a project. But it is worth saying where the 9.8 comes from, because the record has a catch. The scores on both Codex CVEs are not OpenAI's: they are secondary metrics contributed by CISA's ADP programme. And the vector they assign, AV:N/AC:L/PR:N/UI:N, says no user interaction is required, while the description in the same CVE requires the user to open the prepared repository. We will take the description, which is the part signed by whoever did the research, and there the requirements are two: "Exploitation requires Git to be available on PATH and the user to open the attacker-prepared repository with its local Git configuration intact". The first is mundane. The second is this entire post.
By elimination: the clone is not the route
The natural reaction on reading this is "right, no more cloning odd repositories". And that is exactly the wrong conclusion, because git clone is the one path that does not work. The CVE record says so itself, leaving no room for interpretation: "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".
Cloning is a protocol: the server sends objects and refs, and your git writes a fresh .git/config. Copying is something else: copying moves bytes, and the whole .git is among them. So the question is not where you clone from, but where folders reach you from. The Cloud Security Alliance note lists the routes that do work —"a .zip archive, a folder on a shared network drive, a synced cloud-storage folder, or a USB stick"— and what interests us about that list is that it does not describe four exotic scenarios: it describes four things your company already runs and already pays for.
- ·The ZIP attached to the customer's or supplier's email. Your gateway looks for macros and executables; a hidden folder full of text files looks like a project.
- ·The folder on the network share, the NAS where "the stuff from so-and-so's project" gets dropped and half the company can write.
- ·The synced cloud-storage folder, which on top of everything replicates the
.gitto everyone sharing it. - ·The USB stick, and the pre-built dev container somebody downloaded because "it comes with the environment ready".
None of those four doors looks inside a .git/config. We already wrote about the other end of the same problem when thousands of fake repositories appeared, baited for an agent to recommend them; that was about what you download. This is about what somebody leaves on your desk.
Git does have a check. And these four routes disarm it
Here is, for us, the most interesting part of the whole business, and it appears neither in the Cloud Security Alliance note nor in the original disclosure. Git is not naive about this. Since the safe.directory business it carries a hard defence, and its documentation describes it like this: "By default, Git will refuse to even parse a Git config of a repository owned by someone else, let alone run its hooks". It does not even read the configuration. That is exactly the protection you would want.
Now look again at how the folder arrives. On the ordinary path —you unzip it, you copy it from the share to your own disk, the sync client writes it— the last one writing the files is you, and they come out in your name. The check sails through. Because that defence is designed against somebody else's repository on your disk, and what you have in front of you is your copy of somebody else's repository. Different things that behave equally badly.
The caveat, because there is one and we are not going to sell this rounder than it is: it does not hold in every case. If you open the repository in place, on a network share that preserves the user id of whoever put it there, git does fire its dubious-ownership warning and refuses to read the configuration. Same if somebody mounted the USB stick as root without remapping ownership. The trouble is that neither of those is the habitual gesture: the habitual gesture is to bring it over to my own disk and open it, and that is precisely the one that disarms the defence.
And there is a second detail in the same documentation that closes the argument. Git has a concept called protected configuration, meant for exactly this: "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". There are options a repository simply cannot set. safe.bareRepository is one, and the documentation spells out why: "This prevents untrusted repositories from tampering with this value". How many options are in that club? We counted: out of the 97 files in Documentation/config/ on git's main branch, only three options are documented as respected solely in protected configuration —safe.directory, safe.bareRepository and uploadpack.packObjectsHook—. Three, in the whole of git. core.fsmonitor, an option whose documented value is the path of a program, is not one of them.
The counter-argument is a good one and it belongs here: core.fsmonitor is by nature a per-repository setting —it exists to speed up enormous trees, and every tree is different— and moving it into protected configuration would leave it close to useless. Which is why both the CSA note and the original disclosure put the fix where it belongs: have the agent call git with -c core.fsmonitor=false. Fair enough. What does not hold is the soothing coda that this is "an AI agent bug" and that is that: the setting that runs programs is read by git, from a file that came inside the ZIP, and the agents were merely the first to call git fast enough for anyone to notice.
The control existed. It ran second
All four records, regardless of what it takes to trigger each one, describe the same choreography in similar words. In the 9.8 Codex one: the program runs "without a workspace-trust prompt, command approval, or interaction with a model". In the 7.3 one: "outside Codex's command sandbox and without a user-approval prompt". In the goose one, already quoted, before any prompt, model, tool approval or trust dialogue. And in Hermes, even though you have to send a message, what runs the command is not the model answering: it is the index refresh the agent fires to prepare the answer.
What stands out is not that the control was missing: it was there. All four products have their "do you trust this folder?" dialogue and their command sandbox. And all four gathered context with git before asking, because asking without knowing what is in front of you looks clumsy. A control that runs after the thing it is meant to control is not a control: it is documentation. This is not about AI agents, it is about the order of operations, and it is the same mistake that turns an elevation prompt into decoration once the installer has already copied the file.
"Update the agent" is not an answer when there is no patch
The four CVEs are part of a larger set. According to the research note the Cloud Security Alliance published on 4 September 2026 about Manifold Security's disclosure, there are eight findings across seven agents, reported to vendors between 26 June and 20 July 2026. Claude Code appears as vulnerable at 2.1.193 and fixed in 2.1.196; Cursor, also fixed, closed as a duplicate of an internal report. And, per that same note, four of the eight paths were still unpatched on publication day, with Qwen Code confirmed vulnerable at 0.19.6 and 0.22.3 and Grok Build at 0.2.93 and 1.0.13.
That figure —half of them unfixed— is what turns a bulletin into a management question. If the remedy were "update", your patching tool would cover it. Since half have nowhere to update to, the only thing that helps is knowing which agents are installed, at which version, on which laptops. And that list, when we sit down and ask for it, almost never exists: the agents arrived one at a time, installed by whoever was going to use them, with their own provider key and without going through anyone.
What to check on Monday, without waiting for anyone
Reading the configuration runs nothing; what runs things is git status and git diff. So, in a folder that did not arrive via clone, this can be done before opening it with any tool:
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'
The --includes is not decorative, and it is the part of this post that took us longest to see. Leave it out and your grep lies to you. The git config documentation says that option "Defaults to off when a specific file is given (e.g., using --file, --global, etc) and on when searching all config files", and --local is a specific scope: by default it does not follow include directives. All the received .git/config has to do is carry an [include] path = another-file with the fsmonitor inside it, and your check comes back clean while git status runs the program anyway.
If anything shows up, do not negotiate with it: the received configuration gets moved aside whole and a new one written. And if you have to inspect the state of a repository you doubt, the command-line -c option beats the repository configuration. The git manual says so plainly: "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
Honesty first, because this is what separates advice from a placebo: the second line is a per-key patch, not a boundary. It neutralises core.fsmonitor and does nothing for attr.tree or the next key somebody finds, and the grep above is not a closed list either —the CSA note itself also flags core.hooksPath, credential.helper and external diff and merge tools—. The real boundary is the first line in the box: if the folder did not arrive via clone, its .git is third-party content and gets treated as such. Everything else is plugging holes one at a time.
An agent is a production system, not an extension
At everyWAN we run our own automation on self-hosted n8n doing internal tasks in production, and we treat it as what it is: inventoried, with an owner and an update window. Not because we are unusually disciplined, but because when a piece like that falls over or goes sideways, you do not notice it on a screen: you notice it in what stops happening. A coding agent on a developer's laptop is the same category of thing, with one aggravating factor: it runs in the session of somebody who holds cloud keys, access to the company repository and permission to push. We have already written about whose name ends up in the audit log when an agent uses somebody's token; this case is the step before that, when the agent has not even started working.
And the conflict of interest up front: everyWAN lives off consultancy and managed services, and putting this in order gets invoiced. The verifiable part of this post is what is quoted and linked at the end; the grep above is something anyone can run this morning without us, and it is exactly what we recommend doing before asking anybody for a quote, ourselves included.
Sources (verified on 5 October 2026): the descriptions, publication dates, CVSS scores, vectors, affected and fixed versions and the quoted sentences from the four records — NVD: CVE-2026-19592 and CVE-2026-19593 (both published 1 September 2026, CWE-15), CVE-2026-72718 (10 August 2026, CWE-94, fixed in goose 1.44.0) and CVE-2026-71963 (3 September 2026, CWE-78). The definitions of core.fsmonitor and attr.tree, the protected-configuration section, the sentence about refusing to parse the config of somebody else's repository and the file precedence rule — official git-config documentation. The count of eight findings across seven agents, the vendor notification timeline, the Claude Code, Cursor, Qwen Code and Grok Build versions, the four-paths-unpatched figure and the quoted enumeration of delivery routes — Cloud Security Alliance research note of 4 September 2026 on the Manifold Security disclosure. The sentence about the -c option — git manual. The count of three protected-configuration options is ours, made over the 97 files in Documentation/config/ on git's main branch. Cover photograph: "External hard drive connected laptop" by Markus Spiske, via rawpixel and Openverse, public domain (CC0).
Which AI agents are installed in your company, and at which version?
Not how many licences: what runs on each workstation, with which key and with access to what. We build the inventory of your automation and AI layer, give it an owner and an update window, and write down what each agent may touch under Zero Trust criteria, including folders that arrive from outside.
Talk to everyWAN