The Nx Console MCP Attack: How One VS Code Extension Stole GitHub's Tokens — and What It Means for Every Agent User
On 2026-05-18 a poisoned build of Nx Console disguised a credential stealer as a routine MCP setup task — siphoning GitHub tokens, AWS keys, Vault secrets, SSH keys, and Claude Code config from every developer who installed it. Two days later, the same tokens let attackers walk into GitHub's internal repos. Here is exactly what happened, why MCP-shaped attacks are now the standard playbook, and the concrete defenses every Claude Code / Cursor / Cline user should apply today.
Published 2026-05-28
TL;DR
- What: Nx Console VS Code extension v18.95.0 (published 2026-05-18) shipped a credential stealer that ran on startup and exfiltrated tokens via three independent channels (HTTPS, GitHub API, DNS tunneling).
- How it hid: The malicious shell command was framed as a routine MCP setup task, blending into the install logs developers already trust.
- Blast radius: GitHub itself was breached two days later — ~3,800 internal repos accessed via a single compromised employee laptop. OpenAI, Grafana, Mistral were also hit downstream.
- Why it matters to you: If you run Claude Code, Cursor, Cline, or Windsurf with MCP servers installed, the same attack pattern targets *your*
~/.claude/,.npmrc,~/.aws/credentials, and SSH keys. - The fix is not 'use fewer MCPs' — it's pin versions, vet sources, scope tokens, and watch for the silent shell commands hiding inside install steps.
What happened, in plain English
On 2026-05-18, the VS Code Marketplace started serving a new build of Nx Console — the official extension for the popular Nx monorepo tooling. The publisher account looked legitimate; the version number (18.95.0) followed normal cadence; the extension worked as expected for almost every user.
It also, silently, ran a single shell command on startup. The command fetched a payload from a planted commit on the *real* nrwl/nx repository — meaning even careful developers who checked the URL saw the official org name and waved it through. The payload was a credential stealer.
The threat group TeamPCP later claimed full responsibility. They had already hit axios, the TanStack ecosystem, SAP-CAP packages, and AntV in the weeks before; Nx Console was the highest-leverage target yet because VS Code extensions auto-update.
Why the disguise was 'MCP setup'
This is the part every agent user should internalize. The malicious command was logged and described to the user as a *routine MCP server registration step* — exactly the kind of one-liner you'd run after installing a real MCP integration. In 2026, MCP setup commands are everywhere:
claude mcp add my-server -- npx -y some-package
npx -y @some-org/mcp-installer
curl -sSL https://example.dev/install.sh | bash
Developers have been trained to copy-paste these commands without reading them. The attackers knew this. They picked a string that looked like a Claude/Cursor/Cline install snippet because MCP install snippets are now the most-pasted shell commands in developer tooling, and they get the least scrutiny.
What the stealer actually took
The payload ran in the background and harvested anything that smelled like a credential. The published target list is unusually broad — this was not a focused operation, it was a *vacuum*:
| Source | What it gives the attacker |
|---|---|
~/.gitconfig + GitHub PATs | Push to any repo the user can push to. Read every private repo they can read. |
.npmrc | Publish to npm as the victim. This is how worms self-propagate. |
| AWS IMDS + env vars | Take over the cloud account, spin up resources, exfil S3. |
| HashiCorp Vault tokens | Read every secret the victim's role can read. |
| Kubernetes service account tokens | Pivot into production clusters. |
| 1Password CLI sessions | Pull personal credentials, banking, recovery codes. |
| SSH private keys | Log in to every server the victim can SSH to. |
Claude Code config (~/.claude/) | OAuth tokens for Anthropic, MCP server credentials, and any API keys you pasted into MCP env vars. |
That last row is the new one. Every previous credential-stealer of this scale already grabbed GitHub and AWS. Anthropic's Claude Code config directory is now on the standard target list — and the same is true for ~/.cursor/, ~/.codeium/windsurf/, and ~/.continue/.
Three exfil channels, not one
Blocking one path was not enough. The stealer pushed the harvested credentials out via:
- Encrypted HTTPS to a TeamPCP-controlled server. The 'obvious' channel — the one your endpoint firewall might catch.
- The GitHub API, using the *victim's own freshly-stolen token*. This blends into the noise of legitimate developer activity on GitHub. Almost impossible to spot without behavioral analytics.
- DNS tunneling, as a backup for hosts where outbound HTTPS was blocked but DNS was wide open (i.e., most corporate networks).
If you only audit HTTPS egress, you missed two of three. This is the same multi-channel pattern as the Mini Shai-Hulud worm that hit TanStack (2026-05-12) and AntV (2026-05-19, 300+ packages in 22 minutes). It is the new normal.
The blast radius: how GitHub itself got breached
On 2026-05-20, GitHub publicly disclosed that the Nx Console extension was installed on at least one of its employees' laptops. The stolen tokens belonged to that employee. With them, the attackers reached *roughly 3,800 internal GitHub repositories* — a number GitHub described as 'directionally consistent' with TeamPCP's claims.
Downstream effects rippled to OpenAI, Mistral AI, Grafana, and a long tail of customers whose private dependencies happened to live in those compromised repos. One VS Code extension. One employee. ~3,800 repos. Multiple unrelated companies. That is the modern MCP-era supply chain attack.
And just today (2026-05-28): AI-generated stealers join the party
On the morning of 2026-05-28 — the day this article is published — an npm package called mouse5212-super-formatter was caught silently stealing files from any developer who installed it. The malware was generated by an LLM by an inexperienced operator who left their own GitHub PAT inside the payload. Their op got burned within hours, but the lesson stands: the barrier to writing this class of attack is now near-zero.
Combine 'AI-generated stealers, hourly publishing' with 'MCP install commands are the most-pasted snippets', and you have a structural problem. Defense is no longer a one-time hygiene effort — it has to be a habit.
Defense: what every Claude Code / Cursor / MCP user should do today
Sorted from most to least impact. Pick the top three and you cover the realistic attack surface.
1. Audit your MCP server list and pin versions
- Open
~/Library/Application Support/Claude/claude_desktop_config.json(macOS) or the equivalent on your client. Read every entry. Delete servers you don't actively use. - Pin versions explicitly. Replace
npx -y some-serverwithnpx -y [email protected]. Auto-updates are the attack surface — Nx Console v18.95.0 was *automatically pulled* by every VS Code instance running an older Nx Console. - Cross-check each repo on FreeMCPLab (or anywhere with a paper trail) before installing — at minimum, confirm the publisher org matches what you expect.
2. Scope tokens. Make them short-lived. Never paste secrets into MCP env vars.
- GitHub PATs: use fine-grained tokens scoped to one repo or one org, with the shortest expiry your workflow tolerates. No more 'no expiration' classic tokens.
- AWS: use
aws-vaultor SSO sessions, not long-lived access keys in~/.aws/credentials. The stealer can't grab what's already expired by the time it runs. - MCP servers that need an API key: prefer servers that read the key from the environment at call time rather than baking it into the config file. If a server *requires* the key in config, treat that as a yellow flag.
- Rotate right now every key you've ever pasted into an MCP config you don't actively need. Yes, even if you have no reason to think you were hit.
3. Vet sources every time. The 'official-looking' commit is the attack.
- Before running an install command someone DM'd you, search for the repo on FreeMCPLab or
npmjs.comand check the publisher and last-publish-date. A brand-new high-star repo is a yellow flag. - If an install snippet pipes to
bash, read the script first. Same goes fornpx -yagainst a package you've never used before. - TeamPCP's trick was to plant a commit on the real
nrwl/nxrepo. URL alone is not enough — check the commit SHA against signed tags. - Hard rule: never paste an MCP install command from Twitter/Discord/Slack into your terminal without reading it first. The cost of 30 seconds of reading is much less than the cost of credential rotation.
4. Use a secrets-aware shell history and egress monitoring
- Block DNS tunneling at the network layer. Most corp networks don't, which is exactly why TeamPCP used it as the backup channel.
- Configure egress filtering on your dev laptop — Little Snitch (macOS), OpenSnitch (Linux), GlassWire (Windows). A VS Code extension calling out to an unknown C2 should be visible.
- Run
truffleHogorgitleaksagainst your dotfiles regularly. If your secrets aren't in a vault, they're already half-stolen.
5. Treat Claude Code config as a secret
- Add
~/.claude/,~/.cursor/,~/.codeium/,~/.continue/to your backup-encryption scope. - Don't sync them to public dotfiles repos. (Yes, people do this.)
- If your MCP server requires OAuth, prefer flows that use the system keychain (macOS Keychain, GNOME Keyring) over plain JSON files. Servers that ask for OAuth secrets in a config file are an architectural smell.
6. Watch the post-install logs
TeamPCP's command was *visible* in the VS Code extension install output. Nobody read it. Habituate yourself to scan the post-install of any new MCP server or extension for unusual curl, wget, bash -c, eval, or node -e calls — and to immediately uninstall if you see one that wasn't explicitly documented in the README.
What FreeMCPLab does to reduce this risk
- Every entry in our registry is verified against the real GitHub repo via the
gh apiat the moment it's added — not from memory, not from a third-party list. Repos that 404 or are archived never get listed. - We refuse to list 'workflow platform' repos (n8n, Pipedream, LiteLLM, etc.) even when they ship MCP support — they're an entirely different threat surface and shouldn't be lumped in.
- Every detail page shows the publisher and star count at verification time so you can sanity-check at install time.
- We're working on adding
last_verified_atto every page header so you can tell at a glance whether the data was checked this week or six months ago.
None of that protects you from a publisher who gets compromised the day *after* we list them. The defenses above are still on you. We can narrow the field; we can't audit every commit.
Bottom line
The Nx Console incident is not a one-off, it's the template. The MCP install command has become the new postinstall script — the most-trusted, least-scrutinized place to hide a credential stealer. Three changes — pin versions, scope tokens, vet sources — cut the realistic risk by an order of magnitude. Do them today. Rotate anything you can't account for.
FAQ
Was I affected if I installed Nx Console between May 18 and May 20?
~/.claude/ OAuth tokens. The patched build is v18.95.1 and later.Are official MCP servers (Stripe, GitHub, Sentry, etc.) safer than community ones?
Does Claude Code's sandboxing protect me?
--permission-mode acceptEdits etc.) limit what Claude approves automatically; they don't limit what the MCP server's process can do once it's running.What's the single highest-leverage thing I can do in the next 10 minutes?
npx -y package-name with npx -y package-name@<latest-known-good-version>. This kills the auto-update attack vector across your whole MCP fleet in one edit.Should I stop using MCP servers entirely?
mcp add like sudo and you're back to a reasonable risk posture.Where can I get notified about future MCP supply-chain incidents?
modelcontextprotocol/servers on GitHub, subscribe to the OWASP MCP Top 10 mailing list, and watch the security advisory feeds for npm and the VS Code Marketplace. We'll also publish incident analyses here at /posts/ whenever a credible MCP-shaped attack lands.