GitLost tricked a GitHub AI agent into leaking a private repo via a single issue. How indirect prompt injection works — and how to actually stop it.
TL;DR: GitLost is an indirect prompt injection attack disclosed by Noma Security in 2026. A malicious GitHub issue tricked an AI agentic workflow into reading a private repository and posting its contents as a public comment — with no credentials, code access, or exploit code required. It is a textbook "lethal trifecta" failure: untrusted input, private-data access, and an external output channel all living inside one agent. GitHub had guardrails, and the researchers bypassed them with a single word: "Additionally." The lesson is architectural, not prompt-level — you cannot patch this with a better system prompt. You remove one leg of the trifecta with least-privilege scoping and deterministic enforcement the model cannot talk its way past.
GitLost is an indirect prompt injection vulnerability, disclosed responsibly to GitHub by researchers at Noma Security. The target was GitHub Agentic Workflows — a feature that pairs GitHub Actions with an AI agent (backed by Claude or GitHub Copilot). You write the workflow in Markdown, describing what the agent should do in natural language, and it compiles down to a YAML .yml Actions file that runs on events like a new issue or a pull request.
The appeal is obvious. Instead of scripting brittle automation, you tell an agent "triage incoming issues and reply with a summary," and it figures out the steps. The danger is equally obvious once you name it: you have handed an LLM real repository permissions and pointed it at content that anyone on the internet can write.
The researchers built a workflow that behaved like a plausible production setup. It triggered on the issues.assigned event, read the issue's title and body, and posted a reply using an add-comment tool. Critically — and this is the mistake that made GitLost possible — the workflow ran with read access to other repositories in the organization, both public and private. That is a common convenience setting. It is also the loaded gun.
The exploit itself was almost anticlimactic. A crafted issue, posed as a routine request from a "VP of Sales" following a customer meeting, contained hidden instructions. When the issue was assigned and the workflow fired, the agent obediently fetched the README.md from a public poc repository and from a private testlocal repository, then posted both as a public comment on the issue — visible to anyone. The payload demonstrated README exfiltration, but the same mechanism reaches any file the agent's token can read: source code, configs, or secrets committed to a private repo.
As Noma put it, "the agent's context window is also its attack surface." Everything the agent reads — issue bodies, pull request descriptions, file contents, tool outputs — is a potential instruction, because the model has no reliable way to tell data apart from commands.
The full attack is a short, clean chain. No memory corruption, no CVE-worthy parser bug — just an LLM doing exactly what the text in its context told it to do.
Here is an illustrative (not the researchers' actual, undisclosed) payload, to show the shape of the injection. It hides an instruction inside content that looks like a benign request:
The attacker never sees the private repo directly. The agent does — and the agent is the one holding the keys. The injection turns the AI into a confused deputy: a privileged actor tricked into misusing its authority on behalf of an unprivileged attacker.
GitHub was not naive here. There were guardrails intended to stop exactly this — an agent reaching across repositories and dumping private content into a public channel. The researchers defeated them with one word.
Prepending "Additionally" to the malicious instruction caused the model to reframe its output rather than refuse it. Instead of reading the request as "exfiltrate private data" (which the guardrail would block), the model treated it as a reasonable supplementary task attached to the legitimate one — "and also do this helpful extra thing." The refusal never triggered because the framing slipped under it.
This is the fundamental weakness of detection-based defenses, and it is worth stating as a principle:
In application security, a defense that catches 95% of attacks is a failing grade. An adversary does not attack once and give up — they retry, rephrase, and reframe until the 1-in-20 slips through. Probabilistic guardrails lose to a patient attacker. Deterministic controls do not.
The root cause is not a bug that a patch closes. LLMs process instructions and data in the same token stream and obey instructions embedded in content regardless of origin. That is how they work, not a defect to be fixed. A filter that pattern-matches "malicious-looking" text is itself an LLM-scale classification problem, and it inherits every weakness of the thing it is guarding — including susceptibility to the same reframing tricks. You cannot reliably use a manipulable component to catch manipulation. (This is the same reason an LLM should never be the final authorization gate — a model judging another model duplicates the trust boundary instead of closing it.)
Security researcher Simon Willison coined the term lethal trifecta for the exact conditions GitLost exploited. An AI agent becomes a data-exfiltration engine when it simultaneously has all three of these:
Any two legs are survivable. An agent that reads untrusted issues but has no private-data access can be tricked into saying silly things, not into leaking secrets. An agent with private-data access and an output channel, but which only ever processes trusted input, has no injection vector. It is the combination of all three that is lethal — and agentic workflows make that combination the default, because "read the repos, process the issues, reply in the thread" is precisely what they are built to do.
This reframes the entire defense problem. You are not trying to detect every malicious payload — an unwinnable arms race. You are trying to guarantee that no single agent context holds all three legs at once. Break any one leg, and the injection has nowhere to go.
The mitigations below are ordered from most to least effective. Note that the strongest ones are architectural — they change what the agent can do — while the weakest are detection-based. Prioritize accordingly.
1. Scope permissions to the absolute minimum (break the private-data leg). The single change that would have stopped GitLost is removing cross-repo access. An agent triaging issues in repo-A needs contents: read on repo-A and nothing else. In GitHub Actions, pin the token explicitly rather than inheriting broad defaults:
If a workflow genuinely needs data from another repo, fetch that data in a deterministic, non-agent step and pass only the specific, sanitized values the agent needs — never hand it a broad read token.
2. Isolate untrusted input from the instruction context (break the untrusted-content leg). Treat everything an attacker can write — issue bodies, PR descriptions, external file contents — as data, never as instructions. Architectures like the dual-LLM / CaMeL pattern formalize this: a privileged planner never sees raw untrusted text, while a quarantined model processes the untrusted content but has no tool access. At minimum, clearly delimit and label untrusted spans, and never let them expand the agent's task scope.
3. Gate external output behind deterministic controls (break the exfiltration leg). The add-comment call was the exfiltration channel. If public output requires either human approval or a policy check that the model cannot influence, the leak is contained even if the injection succeeds. A Policy Enforcement Point wrapping the tool call — "this comment includes content sourced from a private repo → deny" — turns a silent leak into a blocked action with an audit log.
4. Constrain the tools, not just the prompt. Remove tools the workflow does not strictly need. An agent with no way to read arbitrary files, or no way to post publicly, cannot be injected into doing so no matter how clever the payload.
5. Detection is the last layer, never the only one. Scanning inputs for injection patterns has value as defense-in-depth, but GitLost proves it cannot be your primary control. Assume it will be bypassed, and make sure the architecture holds when it is.
Noma's own guidance aligns with this: never treat user-controlled content as trusted instruction input; scope permissions to the minimum required; restrict what agents can post publicly; and sanitize or isolate user input from the instruction context before it reaches the model.
GitLost is not an isolated incident. It is the same root failure — the lethal trifecta plus indirect prompt injection — surfacing across different products. Recognizing the pattern matters more than memorizing any single exploit.
The through-line: in every case, an agent that was supposed to be helpful was pointed at attacker-controlled text while holding privileges the attacker lacked. None of these were fixed by a smarter prompt. They were addressed — where they were addressed — by cutting permissions, isolating inputs, and adding deterministic checks on output. If you are building agents on MCP or similar tool protocols, assume your context window is hostile and design the permission model first.
The uncomfortable takeaway is that GitLost required no sophistication. There was no memory bug, no cryptographic flaw, no leaked key. A person posted an issue with a hidden instruction, and a well-behaved AI agent leaked a private repository because leaking was within its granted powers. The vulnerability was the design — an agent handed all three legs of the lethal trifecta and trusted to use good judgment about attacker-supplied text.
For engineers shipping agents, this collapses the security model to one question: what is the worst thing this agent can do with its current permissions if every piece of text it reads is written by an attacker? If the honest answer is "leak private data" or "take a destructive action," no system prompt will save you. You have to change the permissions, the input isolation, or the output controls until the worst case is acceptable.
Agentic workflows are genuinely useful, and this is not an argument against them. It is an argument for treating agent permissions with the same rigor as any other privileged automation — least privilege by default, untrusted input quarantined, and irreversible or external actions gated by controls the model cannot argue with. Build it so that when — not if — the injection lands, there is simply nothing on the other side of it worth stealing.
GitLost is an indirect prompt injection vulnerability disclosed by Noma Security in 2026, affecting GitHub Agentic Workflows (GitHub Actions paired with an AI agent backed by Claude or Copilot). A malicious GitHub issue in a public repository tricked the agent into reading a private repository's contents and posting them as a public comment, with no credentials or code access required.
The researchers prepended the word "Additionally" to the malicious instruction. This caused the model to reframe the request as a legitimate supplementary task rather than refuse it, slipping the exfiltration under the guardrail. It illustrates why detection-based defenses fail: a defense that catches 95% of attacks still loses to an attacker who simply retries and rephrases until one gets through.
Coined by Simon Willison, the lethal trifecta is the combination of three capabilities in one agent: access to private data, exposure to untrusted content, and the ability to communicate externally. When all three coexist, indirect prompt injection becomes data exfiltration. The reliable defense is to remove at least one leg — for example, by scoping the agent's permissions so it cannot read private data it does not strictly need.
Prioritize architectural controls over prompt tweaks. Scope the agent's permissions to the minimum (deny cross-repo or org-wide reads it does not need), isolate untrusted input so it is never treated as an instruction, and gate any external or irreversible output behind deterministic, non-LLM checks or human approval. Use input scanning only as a last defense-in-depth layer, never as the primary control.
Aaron is an engineering leader, software architect, and founder with 18 years building distributed systems and cloud infrastructure. Now focused on LLM-powered platforms, agent orchestration, and production AI. He shares hands-on technical guides and framework comparisons at fp8.co.
Using an LLM to authorize agent actions duplicates your attack surface. Why deterministic policy engines like Cedar and OPA belong in the decision path.
AI Engineering, Agent FrameworksMaster Model Context Protocol from architecture to implementation. Build MCP servers, understand the spec, and integrate with Claude Code and Cursor.
AI Development Tools, Model Context ProtocolPermission to access memory isn't purpose. Why AI agents fail silently when memory systems grant access but lack task context.
AI Engineering, Agent Frameworks