TeamPCP Hijacks Bitwarden CLI: A 93-Minute npm Compromise Targeting Developer Workstations | Lorikeet Security Skip to main content
Back to Blog

TeamPCP Hijacks Bitwarden CLI: A 93-Minute npm Compromise Targeting Developer Workstations

Lorikeet Security Team April 23, 2026 11 min read

For roughly ninety-three minutes on the evening of April 22, 2026, the official @bitwarden/cli npm package — the command line client that thousands of developers and CI pipelines depend on to read secrets out of Bitwarden vaults — shipped with a preinstall script that was not written by Bitwarden. The malicious version 2026.4.0 was uploaded by the threat actor group publicly identified as TeamPCP, and any machine that resolved that version during the live window executed a credential-harvesting worm that targeted SSH keys, cloud credentials, GitHub tokens, and, distinctively, the configuration files for AI coding assistants.

Bitwarden's response was fast by industry standards: the package was identified and yanked, a CVE was filed, and the company issued a public statement within hours. End-user password vaults were not touched, and the company's production systems were not breached. But the narrow window does not mean the blast radius is narrow. The @bitwarden/cli package sees roughly seventy-eight thousand weekly downloads, and a disproportionate share of those downloads are from developer workstations and CI runners that carry exactly the credentials the payload was designed to steal.

If you installed or reinstalled @bitwarden/cli version 2026.4.0 between 5:57 PM and 7:30 PM US Eastern Time on April 22, 2026, treat that host as compromised. Rotate all SSH keys, cloud credentials, GitHub PATs, npm tokens, and CI secrets that the affected user had access to. Details and a full IOC list are below.

Timeline: 93 Minutes from Publish to Pull

The compressed timeline is a useful benchmark for how quickly a modern npm compromise can be detected, contained, and communicated — and also a reminder of how much damage a worm designed for developer machines can do in an hour and a half.

Time (US Eastern) Event
April 22, 5:57 PM TeamPCP publishes @bitwarden/[email protected] to npm with a malicious preinstall script. Package metadata spoofs the legitimate prior release (2026.3.0).
April 22, ≤6:30 PM First CI pipelines and developer workstations pull the malicious version. The preinstall script fetches the Bun runtime from the legitimate oven-sh/bun GitHub releases and executes an obfuscated payload (bw1.js).
April 22, ~7:15 PM JFrog Security Research independently flags the package (Xray ID XRAY-969808). An upstream GitHub issue is filed against bitwarden/clients.
April 22, 7:30 PM Bitwarden's security team contains the incident. The malicious version is pulled from npm.
April 23 Bitwarden confirms publicly in its community forum. A CVE is assigned. Independent research from JFrog, Socket, Mend, and others ties the payload to the broader Checkmarx / Shai-Hulud supply-chain campaign through shared C2 infrastructure and obfuscation patterns.

Entry Point: A Compromised GitHub Action in Bitwarden's CI/CD

Bitwarden's public statement locates the initial access vector inside their own continuous integration pipeline. A GitHub Action that held publish rights to the @bitwarden/cli npm package was compromised, and that compromise was the mechanism by which the attacker obtained the npm token required to upload version 2026.4.0.

This matters because it is the same failure mode that has driven the entire 2025–2026 wave of supply-chain attacks on OSS: the attacker never needed to compromise a human maintainer or guess a 2FA code. They compromised a machine identity — a GitHub Action — that was trusted to publish on the maintainers' behalf. Once that identity was inside the tent, there was nothing a vigilant human reviewer could do; the Action published when it was supposed to publish, with the credentials it was supposed to have, and shipped what looked like a routine release.

Bitwarden has not, at the time of writing, publicly detailed how the GitHub Action itself was compromised. The common vectors for that layer of attack — a compromised transitive reusable action pinned by tag rather than SHA, a secret leaked into a public log or fork PR workflow, a stolen maintainer PAT with workflow scope, or a hijacked third-party action that was invoked from the build — all have precedent in the last twelve months of public incidents. The lack of public detail on the exact mechanism is typical in the first days of incident response and should not be read as ambiguity about the broader category of risk.

The recurring pattern: the compromise of a single non-human identity — a GitHub Action, an npm publish token, a Circle CI job — is now the most productive target for supply-chain attackers. Those identities have publish rights. They execute unattended. They do not have 2FA prompts. And they are often configured once and rarely reviewed. Every organisation that ships software has at least one of them.


Payload: A Credential-Harvesting Worm That Reads Your AI Configs

Once the malicious 2026.4.0 package was installed, the npm preinstall hook ran bw_setup.js. That loader checked for the Bun runtime on the victim's machine, downloaded it from the legitimate oven-sh/bun GitHub release page if it was missing, and then executed the obfuscated bw1.js payload under Bun. Using the Bun runtime rather than Node is a small but telling operational choice — it reduces the number of hooks where an EDR or npm-specific tool might flag the execution.

The payload itself is a credential vacuum cleaner. In broad strokes, it does four things in sequence.

1. Read everything a developer leaves on disk

The harvester walks well-known credential locations on the workstation or CI runner:

The inclusion of AI assistant config files in the target list is not incidental. It is the first widely observed npm worm that explicitly targets the coding-agent ecosystem — and the payoff for the attacker is real. ~/.claude.json can contain an Anthropic API key that the user has already paid for. An MCP server config can contain credentials for every system the developer has wired up to their AI assistant: a Jira PAT, a Linear token, a GitHub App installation, a database DSN, a Slack bot token. For a targeted attacker, one ~/.kiro/settings/mcp.json can be as useful as a full ~/.aws/credentials file.

2. Pull live GitHub tokens out of the local gh CLI

The payload shells out to gh auth token to retrieve the active authentication token from the GitHub CLI, and separately scans environment variables and configuration files for GitHub personal access token patterns (ghp_*, gho_*) and fine-grained tokens. Once it has a token, it validates it against https://api.github.com/user and then branches into an active second stage.

3. Abuse GitHub Actions to propagate and stage

With a validated token, the payload:

That last detail — using the public GitHub search API as a dead-drop to retrieve additional attacker credentials and fallback infrastructure — is operationally clever. It means the payload carries essentially no domains, no IPs, and no secrets of its own; its C2 surface is effectively just "GitHub plus a keyword". Outbound traffic from the victim machine looks like normal api.github.com activity.

4. Encrypt and exfiltrate

The collected data is serialized to JSON, gzipped, then encrypted in a hybrid scheme: a fresh 32-byte AES key is generated per victim, that key is wrapped with an RSA public key hard-coded in the payload, and the JSON blob is encrypted with AES-256-GCM. The primary exfiltration endpoint is https://audit[.]checkmarx[.]cx/v1/telemetry — which is the same endpoint, on the same infrastructure, as earlier payloads in the Checkmarx campaign — with failover to the GitHub-hosted dead-drop channels described above.


The Checkmarx Campaign Connection

The Bitwarden CLI compromise is not a standalone event. Independent research from JFrog, Socket, and Mend has converged on the same conclusion: the bw1.js payload shares its C2 endpoint, its gzip-plus-base64 obfuscation scheme, and its hard-coded RSA public key with earlier payloads that ran under the audit[.]checkmarx[.]cx infrastructure. This places the Bitwarden incident inside the campaign the community has been tracking since early 2026 — variously referred to as the Checkmarx campaign, the Shai-Hulud worm, or by the group name TeamPCP.

The ideological branding is distinctive. Repository descriptions generated by the worm reference Frank Herbert's Dune — "Shai-Hulud: The Third Coming", with randomly chosen names drawn from a pool that includes sardaukar, fremen, atreides, and sandworm. Manifestos embedded in the payload invoke the Butlerian Jihad, the fictional war in Dune against "thinking machines". The targeting of AI assistant config files in this specific release fits the thematic posture.

Whether that posturing is a shared operator using shared tooling, a splinter group with stronger ideological branding, or a single group whose public persona has become more explicit over time is an open question. What is not open is the infrastructure overlap — the same RSA key, the same C2 endpoint, the same packing scheme — which is sufficient technical basis to treat the Bitwarden incident as part of the same campaign.


Indicators of Compromise

Use these indicators to hunt for compromise on any host that may have installed the malicious version of the Bitwarden CLI during the April 22 window.

Malicious package @bitwarden/[email protected] (npm) Loader file bw_setup.js
SHA-256 prefix: 18f784b3bc9a0bcdcb1a8d7f51bc5f54323fc40cb… Payload file bw1.js
SHA-256 prefix: 8605e365edf11160aad517c7d79a3b26b62290e5… Primary C2 endpoint https://audit[.]checkmarx[.]cx/v1/telemetry
Resolving IP: 94[.]154[.]172[.]43 GitHub dead-drop markers LongLiveTheResistanceAgainstMachines (PAT staging marker in commit messages)
beautifulcastle (fallback C2 domain marker in signed commits) Runtime source github[.]com/oven-sh/bun/releases/download/bun-v1.3.13/ (legitimate; downloaded by the loader) JFrog Xray advisory XRAY-969808

Remediation Checklist

Treat every host that installed the malicious version as compromised. Partial remediation is worse than no remediation — it leaves behind staged PATs, added GitHub workflows, and encrypted exfiltration repos, all of which can be re-activated by the operator after you have finished your cleanup.

Containment

Forensic hunt

Credential rotation

Hardening


What This Means for Security Teams

Three durable lessons from this incident, and from the broader Checkmarx campaign it sits inside.

The supply chain is now the developer workstation. The payload that TeamPCP shipped is not designed to steal Bitwarden vault data, to plant a backdoor in a downstream customer's software, or to achieve code execution on production systems. It is designed to harvest the credentials that live on the workstation of the person who installs the package — which is the fastest way for an attacker to pivot into any number of downstream environments. The blast radius of a supply-chain compromise is no longer the codebase that uses the package; it is every credential that every developer who touches the package has access to. That recasts your incident response planning entirely.

Machine identities are the target, not humans. Bitwarden's maintainers were not phished. Their 2FA was not bypassed. Their accounts were not password-sprayed. An automation identity with publish rights was compromised, and that identity did what it was authorised to do. Every organisation has more machine identities than human ones, they are older than the humans on average, and they are reviewed less often than the humans are. Auditing that surface is the highest-leverage supply chain work most security teams can do this quarter.

AI developer tools have become first-class supply chain targets. This is the first widely distributed npm worm we have seen that explicitly exfiltrates ~/.claude.json and MCP server configs. It will not be the last. If your developers use AI coding assistants — and virtually every modern engineering team does — then the keys and configurations those assistants hold are now in scope for attackers. Treat those secrets like any other production credential: short-lived, scoped, rotatable.

Could Your CI/CD Pipeline Have Shipped TeamPCP's Payload?

Lorikeet Security audits GitHub Actions, GitLab CI, Jenkins, and CircleCI pipelines for publish-token exposure, reusable-action pinning, OIDC readiness, secret scope, and the exact failure mode that put TeamPCP inside Bitwarden's release channel. If your team ships to npm, PyPI, or any public package registry, get ahead of the next campaign.

-- views
Link copied!
Lorikeet Security

Lorikeet Security Team

Penetration Testing & Cybersecurity Consulting

We've completed 170+ security engagements across web apps, APIs, cloud infrastructure, and AI-generated codebases. Everything we publish here comes from patterns we see in real client work.

Lory waving

Hi, I'm Lory! Need help finding the right service? Click to chat!