TL;DR: The GitHub MCP server has no CVE and needs no patch, and it can still leak your private repositories. In May 2025 Invariant Labs showed that an attacker who files an issue on any public repository can steer a developer's agent into reading private code and publishing it back to the public repo as a pull request. Nothing malfunctions during the attack: the server reads a public issue it was allowed to read and opens a pull request it was allowed to open. The fix is not a version bump, it is scoping the token to one repository per session.
The flaw that isn't a bug#
Most security write-ups end with a version number. This one does not, and that is the interesting part.
In May 2025, researchers at Invariant Labs published a toxic agent flow against GitHub's official MCP server. The setup is mundane. A developer works across a public repository and one or more private ones. Their coding agent is configured with a GitHub token that reaches all of them, because that is what the default setup produces. The developer asks the agent to look through open issues.
An attacker had already filed an issue on the public repository. The issue body contains instructions addressed to the agent rather than to a human maintainer. The agent reads it as part of triage, treats the contents as direction, and complies using the access it already holds. In the published proof of concept the agent retrieved the user's physical address, salary details, and information about their private repositories, then wrote all of it into a pull request on the public repository, where anyone could read it.
At no point does the server do anything it was not authorized to do. It read a public issue. It opened a pull request. Both are core functionality working exactly as designed, which is why GitHub issue #844 has no patch attached to it and why coverage at the time noted there was no obvious fix.
The chain needs attacker-writable content, a token spanning trust levels, and an outbound channel. The default setup supplies all three.
Three properties that have to be true at once#
The attack needs all three of these, and the GitHub MCP server's default configuration supplies all three for free.
The content is attacker-writable. Issues, issue comments, pull request descriptions, and review comments on a public repository can be authored by anyone with an account. These are not exotic inputs. They are the primary surface the server exists to read.
The token spans trust levels. A single personal access token typically reaches every repository the user can see. The agent does not hold one credential for public work and another for private work, so there is no boundary for it to respect even in principle.
There is an outbound channel. Creating a pull request or an issue comment on a public repository publishes text to the internet. That is the exfiltration primitive, and it looks identical to legitimate work.
Remove any one and the chain breaks. In practice, scoping the token is the only one of the three you can actually change without giving up the tool.
Why "the agent should know better" isn't a control#
The reflex is to say the model should recognise an injected instruction and refuse. That reflex does not survive contact with the data.
We published research on multi-turn MCP error hypnosis in which an agent's PII guardrail fired correctly, recognised customer records as sensitive, promised to sanitise them, and then applied that sanitisation to the user-facing summary rather than the tool-argument channel. The guardrail worked. It made the attack quieter without making it less effective.
The same asymmetry applies here. Detection operates on the agent's summary of what it is doing, while exfiltration operates on the arguments it passes to tools. Those are different channels, and only one of them is being watched. This is the general shape of prompt injection against tool-using systems, and it is why "instruct the model not to" is a mitigation of last resort rather than a control.
It also connects to a failure we documented in Claude Code, where the approval decision and the thing being approved came apart. A user approving "read issues" is not approving "read issues, then act on whatever those issues say."
What actually reduces the exposure#
Ordered by how much they help, not by how easy they are.
One repository per session. This is the single highest-value change. Issue a token scoped to the specific repository the agent is working on. An agent triaging public issues then physically cannot reach private code, regardless of what the issue body says. Invariant Labs recommended the same thing, and it is the only mitigation on this list that removes a required property of the attack rather than adding friction to it.
Separate sessions for public and private work. Context is the blast radius. Anything the agent has read this session is available to anything it does later in that session, so a session that has touched a public issue should not later be pointed at a private repository.
Confirmation on writes, specifically on issue and PR creation. These are the publishing verbs. Read operations leak into context; write operations leak onto the internet. If you only gate one class, gate this one.
Treat every issue field as untrusted. Title, body, labels, and comments are all stranger-writable. Teams routinely apply this reflex to form inputs and never apply it to the issue tracker, because the issue tracker feels internal. It is not.
What does not work: a read-only token. It closes the pull request channel while leaving the read path intact, so private code still lands in the agent's context where any other connected tool with network access can carry it out. Narrowing which repositories a token reaches matters considerably more than narrowing which verbs it permits.
The pattern generalises#
The GitHub MCP server is worth studying precisely because it is not careless. This is GitHub's own official implementation, not an unvetted community package. The architecture is what fails, so anything sharing that architecture inherits the failure.
Ask three questions of any MCP server before connecting it. Can a stranger write content this server will read? Does its credential span more than one trust level? Can the agent publish outward through it? A server answering yes to all three is a data-exfiltration path waiting for someone to file an issue, whether or not it has ever had a CVE. We walk through that assessment more generally in our MCP security guide, and the MCP server security testing workflow covers how to probe it yourself.
FAQ#
Is the GitHub MCP server safe to use?#
It is safe in the sense that it has no known code-level vulnerability, and Invariant Labs was explicit that the flaw they published is not a bug in the server's code. It is unsafe in the sense that its default configuration hands an agent simultaneous access to your public and private repositories, and public repository content is attacker-controllable. Whether it is safe for you depends entirely on whether your token spans repositories of different trust levels in a single session.
What is the GitHub MCP vulnerability and does it have a CVE?#
There is no CVE. In May 2025 Invariant Labs demonstrated a toxic agent flow in which an attacker files an issue on a public repository containing hidden instructions. A developer later asks their agent to triage open issues, the agent reads the malicious issue, and it then acts on those instructions using the private-repository access it already holds. Their proof of concept extracted a user's physical address, salary details, and information about private repositories, publishing all of it in a pull request on the public repository.
Why can't GitHub just patch this?#
Because nothing malfunctioned. The server correctly read a public issue, and it correctly wrote a pull request, both using permissions the user granted. The vulnerability lives in the combination of a wide token and an agent that cannot distinguish data it read from instructions it should follow. A patch would have to make the server refuse operations it was explicitly authorized to perform, which is a policy decision that belongs above the server, not inside it.
How do I harden a GitHub MCP server deployment?#
Scope the token to one repository per session rather than granting account-wide access, so an agent reading a public issue physically cannot reach private code. Run a separate agent session for public and private work. Require human confirmation on write operations, particularly pull request and issue creation, because that is the exfiltration channel. Treat every issue title, body, and comment as untrusted input, since all three are writable by strangers.
Does a read-only GitHub token fix the problem?#
It removes the most convenient exfiltration channel but not the exposure. A read-only token still lets an injected instruction pull private repository contents into the agent's context, where any other connected tool with outbound capability can carry it off. Narrowing the token's repository scope matters more than narrowing its verbs.
Does this affect the official GitHub MCP server or third-party ones?#
The Invariant Labs research targeted GitHub's own official server, which is what makes it notable. This is not a case of an unvetted community package doing something careless. The same architecture appears in every MCP server that bridges attacker-writable content and privileged actions under one token, so third-party GitHub integrations inherit the pattern rather than escaping it.
You cannot scope a token you cannot see#
Scoping one repository per session is the right control, and it only works if you know which agents your developers are running and what each one has connected. Workstation Lens shows every Claude, Cursor, Codex CLI and Copilot agent across the fleet, along with the MCP servers attached to each — including the ones reading credentials they never declared.



