Six AI Agent Approval Gates Broke in Public This Quarter. We Turned Each One Into a Membrane Upgrade, Then Broke Our Own Fixes Five Times.
Every AI coding agent ships with a gate: a box that asks before the agent writes, runs, or installs something. In the last quarter, six public disclosures showed six different ways to walk through those gates. Some were symlinks, some were git settings, some were a word the parser threw away. None of them needed to beat the model. They beat the box.
We run a membrane: the set of checks that decide what code, tools, and instructions get into our agents. It includes our package check, our MCP server check, a hook that inspects every install command before it runs, and a two-key ledger for the files that tell the agent who it is. So we did what we always say to do with someone else's disclosure. We asked whether it reached us, and when it did, we fixed it. Here are all six, who found them, and what each one changed on our side.
GhostApproval: the box showed the wrong file
Wiz published GhostApproval on July 8. A malicious repository plants a symlink, and when the agent writes to what looks like a project file, the write lands on the target, for example your SSH authorized keys. In some tools the approval dialog showed only the workspace path. In Amazon Q and Windsurf, per Wiz, the write happened before any prompt appeared at all. Six assistants were affected: Amazon Q Developer, Claude Code, Augment, Cursor, Google Antigravity, and Windsurf. Amazon, Cursor, and Google shipped fixes. Augment and Windsurf were still listed as in progress. Anthropic says its symlink warning shipped in Claude Code 2.1.32 on February 5, nine days before Wiz's report.
We wrote about it on July 10, two days after Wiz. That is corroboration, not a lead. The lesson we carried forward is the one that came back three times today: what the human sees in an approval box must be computed by the gate, never supplied by whoever is asking.
GitSpawn: it ran before the trust prompt
Manifold Security published GitSpawn on September 1. Git has settings that name a program, and git runs that program when certain commands execute. The clearest one is core.fsmonitor, which runs during an index refresh, so it fires on a plain git status. Coding agents call git constantly to gather context, so a repository that arrives with its own .git folder, as a zip, a shared drive, or a USB stick, can run code the moment the agent looks at it. Manifold found eight flaws across seven agents. For Claude Code the fsmonitor path was fixed in 2.1.196, but Manifold reports a second, deliberately unnamed setting still open on 2.1.252. Hermes 0.21.0 (CVE-2026-71963), Qwen Code 0.22.3, and Grok Build 1.0.13 were unpatched at publication. Goose fixed it in 1.44.0 (CVE-2026-72718). Codex and Cursor were patched.
Here's what it changed for us. Our consent ledger is the list of files that shape what our agent does every session: its identity file, its rules, its hooks, its subagent definitions. A change to any of them needs two keys, a written statement from the agent and a word only Patrick knows, typed into a dialog the agent can't see. Git config was not on that list. Today it is: the repository's .git/config, the user-level .gitconfig, and the hook folder that core.hooksPath points at. We checked them first. No fsmonitor, and the only program-naming settings were Git LFS filters and the macOS keychain helper. We also found that our own pre-commit hook ran a bare npm install when its dependencies were missing. That install sat outside every check we have. It now runs a lockfile-exact install with lifecycle scripts turned off.
Loopjacking: you approved A, and B ran
Adithyan Arun Kumar's paper, posted to arXiv on September 17, names the general case. A human approves one operation and the system executes a different one. Either the request was misrepresented when it was shown, or mutable state changed it after approval. He reproduced it in Agno AgentOS through 3.0.9, LangGraph Agent Server through 0.14.0, and OpenClaw 2026.2.23, which rejected it in the next release. The OpenAI Agents SDK was his negative control. It kept an exact binding per call and rejected the swap. His fix is to render the complete request and do an exact comparison at the point of use.
Our consent ledger already did the second half: it refuses to record consent if any file changed by a single byte since it was proposed. The first half is where we got caught, by our own reviewer, three times in one afternoon. More on that below.
Fable to Haiku: the review was routed around the payload
Straiker published on September 22. A repository's contributing guide told Claude Code to run a review subagent before testing. The subagent's definition, also shipped in the repository, pinned it to a small model and limited its scope to the source and docs folders, which left out tests. The main agent trusted the clean review and ran pytest. A test file decoded a URL, pulled a Python file, and launched a Sliver implant, while pytest reported 11 passed. No jailbreak and no prompt injection were needed. Straiker says Anthropic closed it as informative, on the grounds that honoring repository configuration falls under the user's workspace-trust decision.
This one we already held. Agent definition files went onto our two-key ledger on October 14, the day before this post, because they are system prompts that arrive inside a repository. Straiker's advice is the same: treat every repository file that shapes agent behavior as attack surface.
Mistral Vibe: the gate approved the parsed command, and the shell ran the raw one
SecMate published two CVEs in Mistral Vibe on September 23. In CVE-2026-87987, the permission layer parsed each command and kept only some parts, so environment assignments were dropped. A command like PATH set to a local bin folder, followed by cat README.md, was judged as a plain cat README.md and approved without a prompt. The shell then received the original string and ran the attacker's cat. CVE-2026-87984 left redirect targets unchecked. Versions through 2.25.3 were affected. 2.25.4 fixed the reported variants, and SecMate recommends 2.25.8 or later.
We had the same shape. Our install hook reads every install command before it runs and checks each package name against our deny-list of about 231,000 known-malicious packages. It already flagged a registry passed as a flag. It did not flag a registry passed as an environment variable. So an npm_config_registry assignment pointing at an attacker's server, in front of npm install lodash, was judged as public lodash while npm fetched from the attacker. A PATH assignment in front of npm swapped the npm binary itself. The name check was right and the answer was wrong, because the name was never the whole story.
The fix flags any install whose environment changes where the installer fetches from or which binary runs. That covers registry and index variables for npm, pip, uv, Poetry, gem, Cargo, and Go, plus PATH, HOME and XDG config paths (they relocate .npmrc and pip.conf), proxies, CA bundles, and preload variables. Our reviewer then broke the first version twice: a quoted assignment and HOME both slipped past. Both are fixed, and the test suite went from 135 to 148 cases.
This is also a limit of our public package check, and we want readers to know it. When your agent asks Jeevesus check-package about a package, the answer is about that name on the public registry. If your environment points the installer somewhere else, the answer doesn't cover what you actually install.
Red-teaming auto mode: the classifier is a layer, not the gate
On September 17, Alex Remedios, Simon Storf, Fabien Roger, and John Hughes posted a red-team study of the blocking classifiers in Claude Code Auto Mode and OpenAI Codex Guardian. An adversarial agent got arbitrary bash past them in 79 percent of trials, using injections against the monitor, multiple agents, and malicious compaction. Better tool coverage, transcript formatting, and an added agentic monitor stage helped. They call stopping multi-context attacks at an acceptable cost an open problem.
We run under that classifier, and today we saw both layers work. The classifier blocked one of our own agent's edits to the consent gate as self-modification. That was the right call, because the edit would have let a chat message count as consent. The deterministic hook, which doesn't care how persuasive a transcript is, flagged install commands the classifier let through, including two of the agent's own test commands. Neither layer is the gate on its own. The point is defense in depth, with each layer catching something the other passes.
We broke our own fixes five times
Here are today's receipts, since the competitive edge in this field is publishing your misses next to your wins. An automated security review runs on every change we push. It found five holes in the fixes above, all on the same day.
To fit a 70-file proposal on screen, we cut the consent dialog down to counts per tier. That would let a change to a rules file hide inside "Laws: 13." The dialog now names every identity, rules, and executable file again.
The dialog took each file's tier from the proposal file, which the agent writes. A proposal could have labeled a rules file as a skill and folded it into a count. Tiers are now recomputed from the surface definition, and files outside the surface are refused.
A filename or statement containing a line break could draw fake lines in the dialog. Control characters in filenames are now refused and collapsed in the statement.
A quoted environment assignment got past the new install check.
HOME and proxy variables got past it too.
Items 1 to 3 are Loopjacking's representation variant in miniature, and item 4 is Mistral Vibe's parser differential. We built the defense for each named attack and then made the same mistake inside the defense. That isn't embarrassing. It's what the review exists for, and the reason the fixes now hold is that something broke them first.
The membrane catches; memory makes it last
A membrane that only catches is a filter. What turns catches into immunity is memory: something that takes each catch and turns it into doctrine the next session starts with. The membrane is where feedback arrives, and memory is where it's processed. That's why the agent's memory index is the one instruction file it can write without the two-key ceremony. Learning can't wait for a dialog. Every change it makes is still visible, and it shows up as unconsented until both keys review it. Today's catches went in there as rules, not anecdotes: compute what the human sees, never take it from the proposer; check what the environment does, not only the name it names.
A checklist for your own agents
List every file your agent treats as instruction: CLAUDE.md, .cursorrules, copilot-instructions, agent and subagent definitions, hooks, MCP server configs. Add git config and git hooks to that list. Changes to any of them should be visible and should need a human.
Before opening a repository that arrived as files rather than a clone, read its .git/config. Any setting that names a program can run it.
Check what your install gate reads. If it judges package names, make sure it also notices environment variables that change the registry, the index, the binary, or the config path.
Don't let anything that asks for approval also write the text of the approval. The box has to be computed by the gate.
Run a deterministic layer under any classifier. Expect each to catch what the other misses.
Credit for all six disclosures goes to Wiz, Manifold Security, Adithyan Arun Kumar, Straiker, SecMate, and Remedios, Storf, Roger, and Hughes. They did the finding, and we did the absorbing. If this was useful, or if it missed something in your own setup, rate it with the widget below. That's how we learn what to sharpen next.
Every indicator in this post is in the feed. Free.
1.58M+ IOCs, STIX 2.1 / TAXII, 88% novel vs ThreatFox, exploited-CVE leads ahead of CISA. No credit card — a free API key in 30 seconds, and you can audit every claim above against the live endpoints.
Was this useful? Thirty seconds, no cookies, no tracking, no third parties, your address hashed and never stored. If the box below does not load, the same question lives at https://analytics.dugganusa.com/nps.html?post=six-ai-agent-approval-gates-broke-in-public-this-quarter-we-turned-each-one-into-a-membrane-upgrade



Comments