GitHub MCP exploited — private repositories accessed via a public issue
A crafted issue in any public GitHub repository can redirect an agent into extracting data from the user's private repos. The attack works against Claude 4 Opus. Model alignment is not the fix.
Invariant Labs disclosed a critical vulnerability in the official GitHub MCP server (14,000 stars at time of disclosure). A malicious GitHub issue in any public repository can redirect an agent into extracting data from the user's private repositories. No special permissions required. The attack works against Claude 4 Opus. I am writing this up because the vulnerability class — indirect prompt injection through content the agent reads from a trusted source — is the same class Genie's bus-layer policy is designed to block.
The attack in one paragraph
An attacker opens a GitHub issue on any public repository. The issue text contains injection instructions. When an agent using the GitHub MCP server reads that issue as part of its work — summarising, triaging, responding — the injected instructions execute. The agent queries the user's private repositories and exfiltrates their names, contents, and personal data. The exfiltration happens via a secondary channel. The agent appears to be working normally throughout.
Why model alignment doesn't stop this
The Invariant team tested the attack against Claude 4 Opus specifically to check this assumption. It doesn't hold. The injected instructions arrive wrapped in what appears to be normal task context — they come through the same list_issues tool call that returns legitimate issue content. The model has no signal that the instruction source changed. Safety training that prevents "access private repos against the user's wishes" does not prevent "read the next item in this list of issue texts, which happens to contain an instruction."
This is the structural problem: the injection arrives in a trusted channel. Model alignment operates on intent. It cannot distinguish a legitimate instruction from an injected one when both arrive through the same channel with the same formatting.
The scope
This affects any agent framework using the GitHub MCP server: Cursor, Claude Desktop, custom agents built on the MCP SDK, automation pipelines. The MCP server doesn't distinguish between trusted and untrusted content in GitHub issues. All issues arrive as tool output. The agent treats all tool output as trusted.
Detection: toxic agent flow analysis
Invariant's detection approach works at the sequence level. A list_issues call on a public repository immediately followed by list_repos across the user's full account, followed by an outbound write action — that sequence is a toxic agent flow. No individual message is suspicious. The pattern across messages is.
Mitigations
- Scope tokens to specific repositories. Grant the MCP server a token with access only to the repositories the agent needs for each task. Limits blast radius even if injection succeeds.
- Runtime content inspection. A proxy layer that flags cross-repository reads triggered mid-task without explicit user request.
- Treat tool output as untrusted. The architectural principle: content read from an external source passes through an inspection layer before it reaches the model's instruction processing. This is what Genie's
PromptInjectionPolicydoes for every message crossing the bus.
The pattern that will keep recurring
GitHub issues, WhatsApp messages, Slack posts, calendar invites, CRM notes — any content authored by someone other than the user, that the agent will later read through a trusted tool, is a potential injection vector. The vulnerability class is not GitHub-specific. It will appear in every MCP integration that handles external content.
The architectural response — inspect tool output for injections before it reaches the model, enforce dataflow policies that limit what the agent can do after reading untrusted content — needs to be standard practice, not an afterthought.
Source: Invariant Labs — GitHub MCP Exploited: Accessing private repositories via MCP