Case studies / GitHub MCP server (as described by Simon Willison)

One tool, three legs: how an issue tracker became a data leak

A single MCP tool could read public issues anyone can file, reach private repositories and open pull requests. Together, that is a path for stealing data.

8 min study timeLast reviewed Markdown version
When
2025, discussed by security researchers and in Simon Willison's June 2025 write-up
What the tool could do
Read issues in public repositories (which an attacker can write), read information in private repositories, and create pull requests
What went wrong
One tool combined private data, untrusted content and an outbound channel, so hidden instructions in an issue could steer the agent
Reality
No model bug was needed. The danger came from the combination of capabilities
Typical fix
Vendors usually fixed such cases by locking down the outbound channel so stolen data had no way out

What happened

Security researchers showed that an agent using the official GitHub MCP server could be turned against its own user. The server let one agent read issues in public repositories, read information in private repositories, and create pull requests. In Simon Willison's description, that single MCP could read public issues that an attacker could have filed, access private repository data, and create pull requests in a way that sends that data out.

The attack needs no break-in. An outsider files an issue with hidden instructions. Later, a developer asks the agent to look at the open issues. The agent reads the attacker's text as part of its work, follows the instructions in it, reads private data and writes it somewhere the attacker can see. The model did what models do: it followed instructions that reached it.

Willison named the pattern the lethal trifecta: access to private data, exposure to untrusted content, and the ability to communicate outward. He reported that this kind of exploit had been shown against several production systems within weeks, and that most were fixed by closing the outbound channel.

Why it happened: a design reading

  • Untrusted content looked like normal input. An issue is text from a stranger, but to the agent it was just another thing to read.
  • One tool held all three legs. Nothing separated reading outsiders' text from reaching private data and from writing outward.
  • The prompt could not carry the burden. A line saying "ignore hidden instructions" is one more instruction in the same stream, and models do not reliably tell content from commands.
  • Convenience beat least privilege. Mixing and matching tools is easy with MCP, and each tool alone looked harmless.

The same shape in support

Support teams read untrusted text all day: tickets, forms, emails, chat attachments. They often have customer records and a way to reply. Security vendors have reported the pattern in that setting, including a 2025 demonstration in which an agent triaging a support ticket queried a production database and posted private tokens into the ticket thread, and later cases involving form inputs processed by customer-facing agents. Those are secondary summaries, so check the original advisories before quoting details.

Design lessons

  1. Test every agent for the trifecta. If it has private data, untrusted input and an outbound path, redesign it.
  2. Break one leg. Remove the outbound channel for this task, remove access to private data, or keep untrusted text away from the tool-using agent.
  3. Do not buy safety from a detection rate. A guardrail that catches most attacks still lets some through, and a data leak needs only one.
  4. Scope per request. A summarizer does not need the customer database or the send button.
  5. Log and review tool calls so a leak can be found and traced.

How to build it better

  • Split the work: a reader agent with no private access processes tickets and returns a short structured summary, and an actor agent with limited tools acts on that summary, never on the raw text.
  • Allow replies only to the verified requester, with links and images stripped.
  • Require human approval for any action that sends data or changes a record.
  • Review tool descriptions and servers as you would dependencies (module 8).

Try it

Pick an agent you run or plan. Write down the private data it can reach, the untrusted text that reaches it, and every way it can send something out. Then change the design so one of the three answers becomes "nothing", and say what that costs in convenience.

Page history (1)
  1. New
    November 3, 2026 Release 2026.11.03

    How a single MCP tool combined private data, untrusted content and an outbound channel, and what it teaches about support agents.

Full change log