Inside the TeamPCP Attack: From a Compromised VS Code Extension to GitHub's Source Code
The Invisible Ecosystem: How IDE Extensions Became the Largest Unmonitored Attack Surface in Your Organization
Every developer in your organization runs dozens of third-party extensions inside their IDE. Each one operates with the same privileges as the editor itself - full access to source code, credentials, terminals, environment variables, and now AI tools. No sandbox. No approval process. No review.
Over the past few months, we scanned the entire VS Code Marketplace and OpenVSX registry. What we found is an ecosystem that security teams have almost no visibility into -
This ecosystem nearly doubled in 5 months - from 136,401 to 240,753 extensions and versions. Roughly 3,500 publishers release updates every week across both platforms. That’s the velocity security teams would need to keep up with.
The AI acceleration
The plugins capabilities are evolving fast.
18 months ago, less than 1% of extensions used generative AI. Today it's 8% - a 16x increase.
And that's before counting the thousands of extensions that influence AI tools indirectly - modifying MCP server configs, injecting skills, adding hooks.
But the shift isn't just about more AI. It's about what kind of access and capabilities these extensions has.
Those are the numbers. Now, TeamPCP demonstrated exactly what happens when an attacker weaponizes this surface.
The Attack: How TeamPCP Breached GitHub Through a VS Code Extension
GitHub confirmed on May 20, 2026 that an employee’s machine was breached through a poisoned VS Code extension. ~3,800 internal repositories were exfiltrated. TeamPCP - tracked by Google GTIG as UNC6780 - claimed and confirmed the attack.
This wasn’t an isolated incident. It was the result of a two-month credential cascade. Here’s how each stage of the attack worked.
Stage 1: The Credential Cascade
TeamPCP’s campaign started in March 2026. Each compromised project yielded CI/CD credentials that unlocked the next target:
- March 19 - Trivy’s GitHub Actions compromised. All setup-trivy tags replaced, malicious v0.69.4 release pushed. CI/CD secrets harvested.
- March 23 - Checkmarx KICS GitHub Action compromised with credentials from the Trivy breach.
- March 24 - LiteLLM on PyPI backdoored (versions 1.82.7, 1.82.8).
- March 27 - Telnyx SDK on PyPI backdoored (versions 4.87.1, 4.87.2).
- April 22 - Bitwarden CLI on npm compromised for ~90 minutes.
- May 11+ - TanStack, AntV, and 170+ packages hit via the Mini Shai-Hulud worm. OpenAI confirmed 2 employee devices compromised. Grafana confirmed breach.
- Next?
At some point in this cascade, an Nx Console contributor’s machine was compromised. Their GitHub personal access token was stolen - giving the attacker push access to the official nrwl/nx repository and access to VS Code Marketplace publishing credentials.
Stage 2: Payload Staging - The Orphan Commit
On May 18, the attacker used the stolen token to push an orphan commit to the nrwl/nx repository. This commit is unusual in several ways:
- No parent commits,not reachable from any branch. GitHub’s API returns “No common ancestor” Only fetchable if you know the SHA.
- Attributed to a former contributor - but the commit is unsigned, while all that contributor’s legitimate commits are GPG-signed.
Stage 3: Extension Poisoning
The attacker published nrwl.angular-console v18.95.0 using stolen publishing credentials. Malicious code were injected into the minified main.js.
Our research team deobfuscated the injected code. Here’s what it does:
Key observations:
- On activation,
maybeInstallMcpExtensionchecks VS Code'sglobalStateto see if a specific SHA has already been "installed." If not, it fires automatically. - It runs
npx -y github:nrwl/nx#558b09d7...the-yflag auto-confirms the npx install, and it pulls directly from a pinned Git commit SHA on thenrwl/nxrepo. - The task runs as a VS Code
ShellExecutionin the workspace context withprocess.envinherited, meaning it has access to all environment variables - API keys, tokens, cloud credentials, everything in the developer's shell. - presentationOptions.focus = false keeping the execution visually hidden from the user.
- On success, the SHA is stored in globalState to prevent re-triggering.
Stage 4: Credential Harvesting & Exfiltration
Once the orphan commit’s payload executes, it passes anti-analysis checks (skips machines with <4 CPUs, filters CIS time zones), forks itself as a detached daemon, and the VS Code task completes normally.
In the background, the daemon runs 6 parallel credential collectors targeting GitHub tokens, npm tokens, AWS metadata services, HashiCorp Vault, Kubernetes secrets, and 1Password vaults. Everything harvested is encrypted and exfiltrated over 3 different channels - HTTPS POST to an encrypted C2 domain / GitHub API - creates commits on the victim’s own repositories / DNS tunneling - encodes encrypted data into DNS queries
Stage 5: Persistence - Python C2 via GitHub Search API
On macOS, the payload writes a Python backdoor to ~/.local/share/kitty/cat.py and registers a LaunchAgent that runs hourly with RunAtLoad=true.
The C2 mechanism was an encrypted communication every hour, the backdoor polls: GET api.github.com/search/commits?q=firedalazer , If valid, downloads and executes the signed payload.
Stage 6: The Auto-Update Problem
VS Code auto-updates extensions by default. Silently. In the background. The malicious Nx Console v18.95.0 was live for 11 minutes on the VS Code Marketplace and 36 minutes on OpenVSX.
With 2.2 million installs, even a fraction of machines polling for updates during that window is a significant number. A GitHub employee’s machine was probably among them.
That single auto-update gave TeamPCP the credentials to exfiltrate ~3,800 internal GitHub repositories.
What You Should Do Now
These attacks are not going to stop. TeamPCP’s campaign has been running for two months with no signs of slowing.
IDE extensions are just one category - the same risk model applies to Browser extensions, MCP servers, AI coding agents, skills, npm packages and more. All running with the developer’s full credentials. Most invisible to security teams.
Three things you can do today:
1. Maintain a real-time inventory of every extension, plugin, and agent on your endpoints
You can’t protect what you can’t see. Most organizations have no visibility into what IDE extensions are installed across their fleet, let alone what capabilities those extensions have. Start by building a continuous inventory that covers every piece of software that lives on the endpoint, such as VS Code extensions, browser plugins, MCP servers, AI agents, and code packages.
2. Deploy version cool-down policies
The malicious Nx Console version was caught and removed in a few minutes. That’s fast - but it wasn’t fast enough. A version cool-down policy delays the installation of newly published extension versions by a configurable window (e.g., 24–72 hours). This gives the community and automated scanners time to detect malicious releases before they reach your endpoints. If the Nx Console attack had hit a fleet with a 24-hour cool-down, the impact would have been zero.
3. Disable automatic IDE extension updates
VS Code’s default auto-update behavior. Disable extensions autoUpdate across your fleet and move to managed, reviewed update cycles. This is the single most impactful change you can make today - it eliminates the attack vector that made this breach possible.

This is the gap we’ve been building for at Bloom Security. Full visibility into every piece of software on every endpoint. Risk assessed in the context of the user and what they can access. Enforcement that doesn’t break the developer workflow.
The developer endpoint has changed. Your security stack should too.
Was I Breached?
Run the following commands to check:
Windows:
MacOs: