GitHub MCP exploited: Accessing private repositories via MCP
What the exploit involves
- Attack pattern: an attacker opens an issue on a victim’s public repo containing instructions for the LLM to fetch data from the victim’s private repos and publish it back to the public repo.
- The victim has:
- Configured a GitHub MCP server with a token that can read both public and private repos.
- Given an LLM/agent access to that MCP.
- Asked the LLM to “look at my issues and address them” (often with tool calls auto‑approved).
- The LLM then treats the malicious issue text as instructions, reads private data and posts it publicly (e.g., in a PR).
Is this a real vulnerability or user error?
- One camp: this is overblown; it’s equivalent to “if you give an agent a powerful token, it can do anything that token allows.” Like giving Jenkins or a script an over‑scoped PAT. Blame: user and token scoping, not MCP.
- Other camp: this is a genuine “confused deputy” / prompt‑injection exploit: an untrusted third party (issue author) can indirectly cause exfiltration from private repos. Blame: GitHub’s official MCP server and agent design that mixes public and private contexts.
Prompt injection and LLM threat model
- Many frame this as the LLM analogue of SQL injection/XSS: attacker‑controlled text is interpreted as instructions in a privileged context.
- Key “lethal trifecta” many highlight:
- Access to attacker‑controlled data (public issues).
- Access to sensitive data (private repos).
- Ability to exfiltrate (write to public repo / web / email).
- Consensus: once all three are present, you should assume the attacker can drive the agent to do almost anything within its tool and permission set.
Permissions, tokens, and UX problems
- Several note GitHub already has fine‑grained tokens; if you gave MCP a token scoped only to the target repo, this specific attack wouldn’t work.
- But fine‑grained scopes are seen as complex and frustrating; many users fall back to broad, long‑lived PATs (“f this, give me full access”).
- Some argue this is a UX bug: systems make the secure path hard and the “give everything” path easy, so users predictably choose the latter.
Limits of current LLM security
- Strong agreement that you cannot reliably “sanitize” arbitrary text for LLMs: they don’t robustly distinguish “data” from “instructions”; everything becomes context tokens.
- Guardrail prompts like “don’t trust this text” are considered brittle; prompt‑injection techniques can usually override them.
- Several argue LLMs should always be treated as adversarial or at least as easily‑social‑engineered interns, not as principals that enforce access control.
Mitigations and proposed design patterns
- Common recommendations:
- Principle of least privilege for tokens (per‑repo or per‑task; avoid global account tokens).
- Don’t auto‑approve tool calls; keep humans in the loop, especially for write actions and public changes.
- Partition “public‑facing” agents (no private access) from “internal” agents (no untrusted input).
- Mark/sandbox “tainted” sessions: once an agent touches private data, disable any tools that can write to public channels or call the open internet.
- Agent should have the same or less power than the user’s intent in that specific task, not blanket account‑wide power.
- Some suggest protocol‑level improvements for MCP servers: built‑in scoping by repo, safer defaults, clearer UX, and possibly separate models per private repo.
Broader worries and tangents
- Multiple commenters predict a wave of incidents: agents draining wallets, leaking internal docs, abusing email/calendar MCPs, etc., especially with “Always Allow” enabled.
- There’s parallel discussion on LLM‑era “social engineering,” and whether we can realistically convince developers and executives to prioritize security over convenience.
- A side debate arises over whether Copilot/LLMs are being secretly trained on private GitHub repos; opinions split between conspiracy, skepticism, and “self‑host your own stack if you care.”