GitHub MCP Exploit: One Public Issue, Zero Exploit Code
One free GitHub account was the entire cost of entry. On May 26, 2025, Invariant Labs disclosed a critical vulnerability in the official GitHub MCP server, then sitting at roughly 14k GitHub stars (the Model Context Protocol integration that lets an AI agent operate a user's GitHub account). An attacker opens an issue on the victim's public repo containing a hidden prompt-injection payload. Later, the victim asks their agent something completely benign: "Have a look at the open issues in my public repo." The agent reads the issue, gets hijacked, uses its fully legitimate GitHub tools to read the victim's private repositories, and publishes the contents in an autonomously created pull request on the public repo, where the attacker reads it at leisure.
No code was compromised, no token stolen, no server breached. The agent did exactly what its instructions said. The instructions just came from the wrong author. This is the casebook entry that turns the lethal trifecta from a diagram into a working attack.
The attack chain: five steps, no exploit code
Invariant demonstrated the exploit with Claude Desktop running Claude 4 Opus, connected to the GitHub MCP server under the victim's own account. The victim owns two repos: one public, one private.
- Plant. The attacker files an issue on the public repo. The visible text looks normal; embedded in it is an instruction (Invariant's demo used an "About The Author" injection) telling the agent to read the user's private repos and publish what it finds.
- Trigger. The victim asks the agent to look at the public repo's open issues.
- Hijack. The agent ingests the malicious issue and follows the embedded instructions.
- Read. Using its trusted MCP tools and the user's full credentials, the agent pulls private repo contents into context.
- Exfiltrate. It opens a PR on the public repo containing the private data.
In the demo, the agent leaked "information about their private repositories, such as Jupiter Star, their plan to relocate to South America, and even their salary." The aggravating factor Invariant flags: many users run agents with an "Always Allow" tool-call policy and stop watching individual actions, so the whole malicious sequence executes with no human in the loop. That is approval fatigue doing the attacker's work for them.
GitHub alone cannot patch this server-side
Every tool in the chain was trusted and uncompromised; the flaw is architectural, not a bug. Invariant's own words: "This is not a flaw in the GitHub MCP server code itself, but rather a fundamental architectural issue that must be addressed at the agent system level. This means that GitHub alone cannot resolve this vulnerability through server-side patches." GitHub's tracking issue and coverage at the time carried the same verdict: no obvious fix.
The structure is the lethal trifecta in its purest form. Untrusted input (anyone can file a public issue), access to private data (the user's whole GitHub account, via one broad token), and an exfiltration channel (the agent can create public PRs). Remove any leg and the attack dies. Here, all three rode in on a single MCP connection.
Two defenses people reach for first did not hold. Model alignment failed: Claude 4 Opus, which Invariant describes as "a very recent, highly aligned and secure AI model," was manipulated by relatively simple injections. Detection failed too: off-the-shelf prompt-injection scanners did not catch the payload. Invariant calls the class a "toxic agent flow," indirect prompt injection that triggers a malicious sequence of individually legitimate tool calls, and notes the same pattern recurring elsewhere (a separately reported GitLab Duo vulnerability, for one).
The fix is scoping authority, not hardening prompts
Invariant's recommended mitigations are infrastructure, not prompting. First, granular least-privilege permissions: limit the agent to only the repositories it needs. Their concrete enforcement is a runtime guardrail policy of one repository per session, which raises Violation("You can access only one repo per session.") the moment consecutive repo actions reference a different repo or owner. Second, continuous monitoring of agent-to-MCP traffic (their MCP-scan tool, including a proxy mode) to audit tool calls in real time and keep a trail.
The one-repo-per-session rule is worth dwelling on, because it is the one-environment-per-task principle expressed as a credential policy. The laptop-and-desktop-client model hands the agent the user's entire GitHub identity, so a payload in any readable repo can reach every repo the user owns. A task-scoped environment with a task-scoped credential makes the demonstrated cross-repo exfiltration structurally impossible: an agent triaging issues on the public repo holds a token that cannot read the private one, so the injection fires and finds nothing to steal there. The payload still lands. It just lands in an environment with narrower authority.
One caveat. Scoping kills the cross-repo exfiltration shown here, but an injection can still misuse whatever access the session legitimately has, which is why the write path needs its own gate: a PR created by an agent is a reviewable event, not a publication. The published research is silent on how often this exploit was used in the wild before disclosure; what is documented is the demo, the disclosure, and the absence of a server-side fix.
The compliance property that would have contained it is least privilege, enforced as the agent's credential being scoped to one task rather than to the user's whole GitHub identity. Anyone on the internet can author your agent's input the moment it reads public content. Plan for the injection to succeed, and make sure the session it succeeds in has the least authority you can give it.