The firehose problem: your coding agent has all your permissions
Why connecting your agent to raw GitHub, Slack, and Drive is the real security bug, and what to expose instead.
Earlier this week a security researcher tricked GitHub's own AI agent into leaking private repositories, and the exploit was a single word. In GitLost, disclosed July 6, Noma's Sasi Levi posted an ordinary-looking Issue in a public repo inside an organization. The Issue body hid instructions in plain English, and to slip past GitHub's guardrails it leaned on the word "Additionally." The agent, wired with cross-repository read access, did as it was told: it pulled contents out of the org's private repos and posted them as a public comment on the issue, where anyone could read them. As the writeup puts it, "any malicious actor can create a GitHub Issue and, in the issue body, hide commands in plain English that GitHub's agent will follow."
It is tempting to read that as a GitHub bug to be patched and forgotten. It is not. GitLost is the shape of the entire pattern, and almost every team running coding agents is standing in it. The bug is not in the agent. It is in what we connected the agent to.
The trifecta is the default configuration, not the edge case
Simon Willison named the failure mode a year ago and it has become the industry's shared mental model. His "lethal trifecta" is three capabilities that are individually fine and catastrophic together: "access to your private data," "exposure to untrusted content," and "the ability to externally communicate." An agent with all three can be talked, by an attacker who controls the untrusted content, into reading your private data and shipping it out.
Now look at how a normal coding agent is set up. You connect it to your repos, your issue tracker, your Slack, your docs, so it has access to your private data. It reads tickets, PR descriptions, commit messages, and design docs, which is exposure to untrusted content, because any of those can be authored by someone you do not fully trust, or by someone who compromised an account, or by a contractor, or by a bot. And it can open pull requests, post comments, call tools, and write files, which is the ability to externally communicate. The trifecta is not an exotic misconfiguration you have to work to create. It is the out-of-the-box setup, the thing the quickstart tells you to do.
The agent is not malicious. It is a confused deputy.
The unsettling part of GitLost is that nothing malfunctioned. The agent did exactly what a competent, obedient executor does: it followed the clearest instruction in its context. It could not tell your intent from the attacker's, because both arrive as the same thing, text in the context window, and nothing in that text is stamped with who is allowed to say it.
That is the confused-deputy problem, and it is decades old. The deputy has real authority and gets tricked into using it on someone else's behalf. What is new is the size of the authority. When you connected the agent to your tools, you did not grant it least privilege. You handed it a token carrying your scopes, and often broader ones, because a shared automation account tends to accumulate access no single human would be given. The agent reads what you can read, across repositories and channels, which means a poisoned instruction in one place can reach data in every place the token touches. One injected ticket, and the blast radius is not a repo. It is everything the firehose is plumbed to.
This is also why the ordinary permission model quietly fails. Your per-user access controls assume a human on the other end who is only supposed to see their slice. An agent connected to everything and driven by whatever text lands in its context is a single reader with a superset of everyone's access, and it will happily surface to the wrong person, or to a public comment thread, whatever it was steered toward.
You cannot scan your way out of this
The reflex, once the incident lands, is to inspect the firehose: scan inbound tickets and commits for injection, add a classifier, filter the prompt. This loses, and GitLost shows why in one detail. The guardrail bypass was the word "Additionally." Detecting malicious instructions in natural language is the same losing game as detecting spam that can rewrite itself, except the attacker gets infinite tries and only has to win once. The design-patterns work Willison draws on points away from detection entirely: once an agent has ingested untrusted input, the thing you must constrain is not the input but what the agent is able to do with it.
So the question is not "how do we catch the bad ticket." It is "why does a ticket the agent read have a path to your private repos at all." And the answer is the firehose.
The firehose problem
Here is the anti-pattern, named so we can stop repeating it. The firehose problem is connecting an agent to your raw sources at your full permissions, so that everything it reads and everything it can reach are the same enormous set. Scanning the firehose treats the symptom. The fix is to not hand the agent the firehose in the first place.
Least privilege for a coding agent was never a narrower OAuth scope. It is a different substrate. Instead of a live credential into Slack, GitHub, and Drive with your reach, the agent reads a curated surface: the decisions, constraints, and context it actually needs for the task, and nothing that doubles as a key to the rest of your company. A poisoned ticket can still say "additionally, exfiltrate the private repos." It just has no repo-wide token to exfiltrate them through, because the agent was never handed one. You did not make the deputy smarter. You stopped arming it.
The same layer, now as a security boundary
We have argued for a governed decision layer on this blog before, but for a different reason: an agent that reads raw sources reconstructs the wrong intent and pulls in noise instead of the decision that binds the task. That was a correctness argument. The security argument turns out to be the same architecture seen from the other side. The reason a curated decision surface makes an agent build the right thing, that it reads what it needs and not the raw pile, is exactly the reason it cannot be turned into a confused deputy: it never held the firehose to begin with. Correctness and least privilege are not two features. They are one property, described twice.
There is evidence the agent will lean on a governed layer when it has one. In a benchmark we published, agents given a governed context layer on top of their codebase access complied with team decisions 95 percent of the time, versus 46 percent on codebase access alone. Two caveats I will not paper over: it measures compliance, not breaches, and it added the layer on top of raw access rather than testing a curated-only agent, so it says nothing about whether you can strip raw access with no loss. What it does show is the part that matters here: when a governed surface is present, the agent takes its decisions from it rather than reconstructing them from the raw pile. Narrowing the raw access underneath is then a deliberate design choice, and the case for narrowing it rests on least privilege, not on this benchmark.
We built Brief to be that surface. It is not a firewall, and it does not replace your scanners or your auth. It removes the reason they are under so much pressure, by being the governed read an agent consults instead of a credential into everything. But the point survives without us. The lesson of GitLost is not that GitHub configured one workflow badly. It is that "connect the agent to your tools" is a security decision disguised as a convenience, and the safe version of it is to expose a surface, not a firehose.
What this does and does not claim
It does not claim a governed layer is a complete security control. You still need authentication, scoping, and monitoring; scanning still has a place at the edges. It does not claim prompt injection is solved, only relocated out of the blast radius. And the compliance benchmark measures behavior, not breaches, so treat it as evidence the pattern is usable, not as a security guarantee. The load-bearing claim is narrow: an agent that can be reached by untrusted text should not also be holding a credential to your entire company, and the durable way to guarantee that is to give it a curated surface to read rather than a firehose to be steered through.
Frequently asked questions
Why do AI coding agents leak private repositories? Because they sit in the lethal trifecta by default: connected to private data, exposed to untrusted content like tickets and commit messages, and able to communicate outward. An attacker who controls any untrusted input the agent reads can instruct it, in plain language, to fetch private data and post it somewhere public. GitLost (July 2026) did exactly this to GitHub's own agent using a poisoned public Issue.
Do AI agents inherit my permissions? Usually yes, and often more. Connecting an agent to your tools typically hands it a token with your scopes, and shared automation accounts tend to accumulate broad access over time. So the agent reads what you can read across every connected source, which is why one poisoned input can reach far more than the place it was planted.
What is the "lethal trifecta" for coding agents? Simon Willison's term for the dangerous combination of access to private data, exposure to untrusted content, and the ability to externally communicate. A standard coding-agent setup has all three, which is what makes prompt injection a data-exfiltration risk rather than just a nuisance.
Can a Jira or Linear ticket really reach my private data? If the agent that reads the ticket also holds a credential to your private repos or drives, yes. The ticket is untrusted content; the credential is the reach; the agent is the confused deputy that connects them. Removing the reach, not scanning the ticket, is the durable fix.
What is the difference between raw data access and a governed context layer? Raw access gives the agent a live credential into your sources at your permissions, so what it can read and what it can reach are the same large set. A governed context layer gives it a curated surface of the decisions and context it needs, so a poisoned instruction has nothing broad to act through. It is least privilege applied to what the agent can see, not just to which scopes are checked.
Does exposing curated decisions instead of raw data actually help the agent do its job? In our benchmark, agents given a governed context layer on top of their codebase access complied with team decisions 95 percent of the time versus 46 percent on codebase access alone, so the agent clearly follows the governed decisions when they are present. That test added the layer to raw access rather than trying a curated-only agent, so it does not by itself prove a curated surface is sufficient alone; how much raw access you can safely narrow underneath is a design choice, and the security case for narrowing it stands on least privilege regardless.
← Back to Blog