Skip to content

GitHub got pwned through one VSCode extension. 3,800 repos.

By Ritabrata Maiti · · 7 min read

Play

GitHub confirmed this week that roughly 3,800 of its internal repositories were exfiltrated after one of its own employees installed a trojanised version of the Nx Console extension for VSCode. The malicious extension came through the official VS Code Marketplace, ran with the editor’s permissions, and quietly handed back the contents of the employee’s repo cache. GitHub has since linked the campaign to the TanStack npm supply chain attack from earlier this month and removed the poisoned extension from the marketplace.

The TeamPCP group is asking $50,000 for the dump. As far as anyone outside GitHub can tell, no customer data has moved.

That is the news. The interesting part is the design that made it possible.

A VSCode extension runs as Node.js code inside the editor’s process. It has the editor’s permissions. That means it can read every file in every workspace you have ever opened, every token in your ~/.aws/credentials, every entry in your SSH agent, and every byte that ever passed through git push. The Marketplace itself has no sandbox model. There has been a feature request open since 2018 asking Microsoft to ship one. The request is still open.

This is not a VSCode-specific complaint. It is the model. Cursor inherits the architecture. Windsurf inherits it. JetBrains plugins run with the IDE’s permissions, just packaged differently. Vim and Emacs have had this problem since plugins were invented; the only reason it never blew up at this scale is that nobody put a marketplace in front of them.

The Marketplace is the part that scales the blast radius. Twelve months ago, a set of malicious extensions disguised as legitimate tools racked up 9 million installs before takedown. A different set posed as cryptominer-laden helpers. A WhiteCobra-flooded batch of twenty-four extensions, one of them with basic ransomware capability, made it onto the marketplace before anyone noticed. And in January, a pair of malicious AI-coding-assistant extensions with 1.5 million installs silently shipped developer data to servers in China.

Add it up. Across the visible-to-the-public campaigns, this is more than 11 million installs of code that should not have been there. The GitHub breach is one well-placed install away from “any of the above got an SRE.”

The threat model in this story is not a clever attacker. The threat model is a checkbox the operator did not read carefully because they were trying to get work done.

A developer at GitHub had an editor open. The editor said: install this extension. It looked like Nx Console; the developer needed Nx Console. They clicked install. Three thousand eight hundred internal repos went out the back door. There is no version of “be more careful” that fixes this. The marketplace is the install surface and the marketplace cannot, in its current shape, distinguish the real extension from the malicious one with the same name.

The fix is at the layer the operator doesn’t have to think about. That is either:

  1. The editor ships a sandbox. Extensions ask for the file paths, network endpoints, and OS capabilities they need. The user reviews a manifest, the same way they review extension permissions in a browser. Microsoft has been promising this since 2018.
  2. The marketplace adds an integrity layer that an attacker cannot forge. Reproducible builds, source mirroring, signed releases. Nothing on the marketplace today provides this end to end.
  3. The user installs nothing they have not personally read or that does not come from a vendor whose source they can audit.

Option 3 is the only one available today. Options 1 and 2 require Microsoft to ship work that has been promised for seven years.

I work on a browser extension, so I want to be clear about what does and does not transfer from this story.

Chromium MV3 extensions are not VSCode extensions. The permission model is real. An extension declares the URLs it can touch (host_permissions) and the capabilities it can use (debugger, storage, nativeMessaging, and so on) in manifest.json. The browser enforces those declarations. An extension that says "host_permissions": ["https://gmail.com/*"] literally cannot reach bank.example.com. The Chrome Web Store review process is not perfect, but it does look at the manifest before publish.

That makes the browser-extension surface meaningfully better than the editor-extension surface for the same class of attack. It does not make it safe. Things to watch:

  • <all_urls> is a real permission Chrome will grant if the user agrees. Many general-purpose extensions ask for it. Browy asks for it (we have to; you point us at any tab you visit). What stops abuse is the next thing on the list.
  • The CRX you download is signed. It is not necessarily the source you read. Chrome Web Store does not require reproducible builds. If the vendor publishes obfuscated code, you are trusting the vendor, not the code.
  • Native messaging is the escape hatch. Browy has a native host that runs on your machine. So does any “remote control” extension, any password manager native bridge, and many “AI assistants.” A malicious extension can ship a clean source repo and a malicious native binary, and the user has no easy way to know.

The list of things that would help Chrome users defend themselves is roughly the same as for VSCode users: a sandbox the user reviews, a marketplace integrity layer the attacker cannot forge, and a habit of installing nothing whose source you have not read.

Browy is open-source under Apache-2.0. The source ships in the release. The agent loop is in one file and the tool registry is in another. A reviewer who reads either file in twenty minutes has read the attack surface. There is no Browy server. The model call goes from your machine to GitHub Copilot via the local Copilot CLI; everything else is local.

The host-touching tools (bash, read_file, write_file, grep, glob, web_fetch) are off by default. To use any of them you have to open Settings, find the tool, and turn it on. The browser-driving tools are on by default but each can be turned off the same way. We ship a debugger banner whenever a session is live, because Chrome makes that mandatory and we are happy with that.

None of this prevents a future me from going rogue and shipping a malicious release. It does mean that anyone who cares can pin a known-good build, audit any future build before installing, and run their own from source. The fix for the marketplace problem is not a better marketplace. It is a habit of looking at what you install.

The short version: when the editor has no sandbox, the only sandbox left is your attention. Spend it before you click install, not after.