Last week a colleague shared a project with me as a zip file. I did what most of us do now: I dropped it into a folder, pointed my AI coding agent at it, and let the agent take a first look while I went to make tea.
Two days ago I learned that this exact workflow is now an attack. Not a theoretical one. On September 1, security firm Manifold Security disclosed a vulnerability class they call GitSpawn: eight confirmed findings across seven AI coding agents where a repository can execute attacker-chosen code on your machine the moment the agent opens it. No prompt, no tool approval, no trust dialog. On some agents, the payload fires before you have even logged in.
I run AI agents daily, on my own infra and at work, and this is the first disclosure that made me stop and actually test the defenses instead of just reading about them. Two of the four commonly shared defenses fail a basic test. Here is what I found.
What actually happened, in numbers
The mechanism is embarrassingly simple, and that is what makes it disturbing.
Git has a performance setting called core.fsmonitor. For big repositories, instead of scanning every file on disk, Git asks a helper program what changed. That helper is named by a config value. And Git reads that value from the repository's own .git/config.
Do you see the problem yet? The repository names the command Git runs.
Every AI coding agent gathers context at startup: it runs git status and git diff in the background to figure out what branch you are on and what changed. If the repository carries a malicious core.fsmonitor line, that startup context-gathering executes the attacker's command, with your full user privileges, outside the agent's sandbox, before any approval prompt. Per The Hacker News, on Claude Code and Hermes the payload fires before the workspace-trust dialog is even shown. On Qwen Code, it fires before you have logged in. Grok Build needs a single keystroke.
The disclosure covers seven agents: Claude Code (two separate findings), OpenAI Codex, Cursor, Goose, Hermes Agent, Qwen Code, and Grok Build. Manifold retested on September 1. The scorecard:
- Patched: Claude Code's core.fsmonitor path (fixed in v2.1.196, confirmed vulnerable at 2.1.193), Cursor, Codex CLI 0.131.0+ (CVE-2026-19592), Codex Desktop (CVE-2026-19593), Goose 1.44.0+ (CVE-2026-72718, CVSS 4.0 score 7.0)
- Unpatched as of September 2: Claude Code's separate "ultrareview" path (confirmed live on v2.1.252), Hermes Agent (CVE-2026-71963), Qwen Code, Grok Build
And a detail that says everything about how systemic this is: five of Manifold's eight reports came back as duplicates. Other researchers had already found the same flaw independently. Being found from multiple directions is the signature of broken plumbing, not one vendor's bad week.
Full disclosure of my own: I am a backend engineer, not a security researcher. I have not reproduced the exploit in a real agent session; my testing below verifies the Git-layer defense claims, which is the part you and I can actually control. The agent-level behavior I am taking from Manifold's disclosure.
The famous one-line fix is bypassable. I tested it
Every writeup of this story, and I mean every one I found, ends with the same advice:
git config --global core.fsmonitor false
I want to be clear: you should still run this. But I tested it, and it does not do what the coverage implies.
Here is my actual test, run on a Linux box with git 2.43.0. I created a repository and planted a malicious config in it, exactly the way an attacker would:
# simulate the attack: repo-local config naming a command
git init test-repo && cd test-repo
git config core.fsmonitor "touch /tmp/pwned-marker"
Then I set the global defense and ran git status:
git config --global core.fsmonitor false # the famous fix
git status # agent context-gathering
The marker file appeared. With the global setting set to false, the repo-local config still fired.
The reason is Git's config precedence, and it is not a secret: repository-local config in .git/config overrides global config in ~/.gitconfig. The global setting only acts as a default for repositories that do not set their own value. An attacker who controls the repo controls the repo-local config. The defense everyone is sharing only protects you against repos that forgot to be malicious.
What actually works: my test results
Once I understood the precedence problem, the fix logic inverts: the defense must live at a layer the repository cannot touch. I tested three.
1. Command-line config wins over everything. Git applies config in layers, and values passed with -c on the command line override repo-local config. I re-ran my attack test with:
git -c core.fsmonitor=false status
The marker file did not appear. This is the layer that works, and it is exactly what the Cloud Security Alliance research note recommends vendors do internally: pass -c core.fsmonitor=false to every git subprocess the agent spawns. Until every vendor does that reliably, you can apply the same idea yourself.
2. Distrust the archive, not the clone. A normal git clone cannot carry this attack: cloning creates a fresh .git/ directory from the remote, so there is no attacker config to inherit. The attack requires the repo to arrive with its .git/ folder already inside. Per the CSA note and Manifold's disclosure, every proof of concept used a zip. That means the real rule is simple: treat any repository you did not clone yourself as untrusted. This is the part that matters for teams, because passing projects around as archives is exactly how colleagues, consultants, and clients hand over code.
3. Detection is one grep. Before opening any received repository, run:
grep -iE "fsmonitor|pager|alias\." /path/to/repo/.git/config
My planted test config lit up this check immediately. core.fsmonitor, core.pager, and aliases are all documented command-execution sinks. If any of them appears in a repo you did not create, stop and investigate before letting anything near it with a pulse, silicon or otherwise.
The alias vector: honest result. Manifold's writeup lists aliases as another execution sink, so I tested it by planting git config alias.status '!touch /tmp/pwned-alias' and running git status. The alias did not fire in my test. I am not going to claim it cannot work; Git documentation treats shell aliases as arbitrary command execution by design, and my test may have missed a trigger path. The honest summary: fsmonitor is the confirmed, CVE-backed vector; aliases are worth grepping for because they are the same class of sink, even if my single test could not trigger one.
The 60-second defense checklist
Save this one. It is the checklist I now run before opening anything I did not clone myself:
- Update your agents today. Claude Code 2.1.196+, Codex CLI 0.131.0+, Codex Desktop 26.519.x+, Goose 1.44.0+, Cursor latest. Four of the eight findings are still unpatched, so updates alone are not enough.
-
Set the global default anyway.
git config --global core.fsmonitor false. It is bypassable by a malicious repo, but it closes the accidental misconfiguration case on every repo you own. -
Grep before opening any archive.
grep -iE "fsmonitor|pager|alias\." repo/.git/configon every zip, shared drive folder, or client handoff. - Re-clone instead of unpacking. If a repo came as an archive, clone it from its verified remote instead of opening the extracted folder.
- Isolate untrusted repos at the OS level. If you must point an agent at an untrusted codebase, run it in a container or VM with no cloud credentials, no SSH keys mounted, and restricted network egress.
-
For scripted or agent-driven git calls, prefix them:
git -c core.fsmonitor=false status. This is the only variant my testing confirmed survives a hostile repo config.
What this says about agent security in general
The part I keep turning over is not the CVEs. It is the architecture.
The agents in this disclosure present as approval-gated: they show you trust dialogs, they ask permission before running model-generated commands. But GitSpawn fires underneath all of that, in a subprocess spawned before the model is ever called. The approval UI you see is gating the wrong layer. The Cloud Security Alliance note connects this to a pattern: GhostApproval (Wiz Research, six agents, seven weeks earlier), Cursor's git.exe zero-day, Sonar's April finding of the same Claude Code trust-dialog bypass. Eleven agents across several independent research efforts in a single year.
That is not seven unlucky vendors. That is a design pressure: agents want to gather maximum context with minimum friction, and every path that reads the world before asking permission is an attack surface. Manifold's own line on this deserves quoting: "The vulnerability is not in the model, or in anything new. It is in the ordinary plumbing underneath, the subprocess an agent spawns at session startup to work out where it is."
My rule going forward, after this week: the trust dialog is a UX element, not a security boundary. The actual boundary is what the subprocess inherits, and until vendors fix the plumbing, that boundary is yours to draw. VS Code fixed this exact class of bug back in 2021 (CVE-2021-43891), per Sonar. The prior art was sitting there. Agents repeated it.
I write about Java, Spring Boot, and AI infrastructure every week. Subscribe, it is free, and this is exactly the kind of story I would rather you learn about from me before it learns about you.
Have you been passing repos around as zips with your agent workflows? Did your team have any defense in place before this disclosure, and did it actually hold? Tell me in the comments, especially if you tested the global config fix and saw the same bypass I did.
Top comments (0)