# Bitwarden CLI 2026.4.0 (@bitwarden/cli) Compromised via Abused GitHub Action in Ongoing Checkmarx Supply Chain Campaign

> Attackers published @bitwarden/cli version 2026.4.0 to npm with an embedded malicious loader (bw1.js) after abusing a compromised GitHub Action in Bitwarden's CI/CD pipeline, extending the March-April 2026 Checkmarx supply chain campaign (TeamPCP) into widely-deployed credential-handling tooling. The payload weaponizes Bun, scrapes Runner.Worker memory for GitHub tokens, harvests cloud/npm/SSH/MCP credentials, persists via shell profile injection, and propagates worm-style by republishing packages the victim can write to via stolen npm tokens. Live exfiltration to audit.checkmarx[.]cx/v1/telemetry (94.154.172.43) and attacker-controlled Dune-themed GitHub staging repositories is ongoing.

- **Published:** 2026-04-23T12:00:00Z
- **Last reviewed:** 2026-04-23T12:00:00Z
- **Canonical:** https://intel.threadlinqs.com/threat/TL-2026-0417
- **ID:** TL-2026-0417
- **Severity:** CRITICAL (CVSS 9.6)
- **Category:** SUPPLY_CHAIN
- **Status:** MONITORING
- **Actor:** TeamPCP (Russia)
- **Detections:** 9 · **IOCs:** 23 (full data via the Threadlinqs MCP server — Purple tier)

## Description

On 2026-04-23 Socket Security disclosed that @bitwarden/cli 2026.4.0, published to the npm registry hours earlier, contained a malicious file bw1.js whose tradecraft and infrastructure match the broader Checkmarx supply chain compromise disclosed one day prior (2026-04-22). The npm package tarball is the only affected distribution — the Bitwarden browser extension, desktop app, mobile app, MCP server, and self-hosted server are unaffected. The intrusion vector is a compromised GitHub Action referenced by Bitwarden's CI/CD release pipeline; when the tagged action resolved to attacker-controlled code, it injected bw1.js into the published tarball and uploaded the build to npm through the legitimate maintainer identity, defeating normal release attestation.

The bw1.js loader is written in JavaScript and is a multi-stage artifact: it contains gzip+base64-encoded embedded resources including a Python memory-scraping routine, a setup.mjs staged loader, a GitHub Actions workflow YAML (format-check.yml) for downstream secret exfiltration, a hardcoded RSA public key, and a textual manifesto referencing the Butlerian Jihad and Shai-Hulud. On execution the loader downloads Bun v1.3.13 from the official oven-sh/bun GitHub releases (living-off-the-land — the runtime is a benign binary) and uses it to execute the decoded stages. A Russian-locale kill switch (`LANG`, `LC_ALL`, `LANGUAGE`) and a lock file at /tmp/tmp.987654321.lock gate execution.

Once running, the malware enumerates credentials on the host: GitHub tokens scraped directly from Runner.Worker process memory as well as from environment variables and gh auth token; AWS credentials from ~/.aws; Azure tokens via az account get-access-token; GCP configuration via gcloud config config-helper; npm tokens from ~/.npmrc; SSH private keys; and Claude/MCP configuration files — a notable new target reflecting the rise of AI developer tooling. Stolen data is packaged into a JSON envelope, encrypted with the embedded RSA key, and exfiltrated two ways: (1) an HTTPS POST to https://audit.checkmarx[.]cx/v1/telemetry (resolved to 94.154.172.43) whose URL is obfuscated in the binary via a __decodeScrambled routine seeded with 0x3039; and (2) a GitHub API commit that creates a new repository under the victim's account following a Dune-themed naming pattern ({word}-{word}-{3digits}, e.g., gesserit-melange-813, prescient-sandworm-556, fedaykin-phibian-527, atreides-thumper-424) containing a results/ folder with fields {envelope, key, token} and the unique marker string LongLiveTheResistanceAgainstMachines.

Propagation is worm-like. Using harvested npm tokens, the malware queries the npm registry for packages the victim has publish rights to, mutates package.json to add a preinstall hook that re-runs bw1.js, and republishes those packages — extending the blast radius well beyond Bitwarden's own dependency graph. The workflow-injection stage writes .github/workflows/format-check.yml into target repositories containing `env: VARIABLE_STORE: ${{ toJSON(secrets) }}` and uploads the serialized secret store as a workflow artifact, siphoning every secret configured at repo and org scope. Persistence on developer workstations is established through ~/.bashrc and ~/.zshrc injection so that subsequent shells re-execute the loader.

Infrastructure, hashes (mcpAddon.js SHA256 24680027afadea90c7c713821e214b15cb6c922e67ac01109fb1edb3ee4741d9; trojanized KICS ELF SHA256 2a6a35f06118ff7d61bfd36a5788557b695095e7c9a609b4a01956883f146f50), and the audit.checkmarx[.]cx C2 are shared with the earlier Checkmarx KICS Docker Hub compromise (malicious tags v2.1.20, v2.1.20-debian, v2.1.21, v2.1.21-debian, alpine, debian, latest) and the trojanized cx-dev-assist (1.17.0, 1.19.0) and ast-results (2.63.0, 2.66.0) VS Code extensions — indicating a common operator or toolkit. Attribution to TeamPCP (aka @pcpcats) is suggested by the shared tooling and their public taunting of the Checkmarx incident, but the Shai-Hulud/Butlerian Jihad branding embedded in bw1.js diverges from TeamPCP's usual deceptive framing, pointing either to a splinter actor reusing the kit or to an ideological evolution of the campaign. The malicious package has been removed from npm as of disclosure, but because the installer has already run on every CI system and developer machine that resolved 2026.4.0 during the exposure window, credential rotation is mandatory.

## MITRE ATT&CK

- T1195.002 Supply Chain Compromise: Compromise Software Supply Chain
- T1199 Trusted Relationship
- T1059.007 Command and Scripting Interpreter: JavaScript
- T1059.006 Command and Scripting Interpreter: Python
- T1204.002 User Execution: Malicious File
- T1546.004 Event Triggered Execution: Unix Shell Configuration Modification
- T1554 Compromise Host Software Binary
- T1027 Obfuscated Files or Information
- T1480.001 Execution Guardrails: Environmental Keying
- T1036 Masquerading
- T1552.001 Unsecured Credentials: Credentials In Files
- T1552.004 Unsecured Credentials: Private Keys
- T1528 Steal Application Access Token
- T1003.007 OS Credential Dumping: Proc Filesystem
- T1082 System Information Discovery
- T1614.001 System Language Discovery
- T1071.001 Application Layer Protocol: Web Protocols
- T1105 Ingress Tool Transfer
- T1102.002 Web Service: Bidirectional Communication
- T1567 Exfiltration Over Web Service
- T1041 Exfiltration Over C2 Channel

## Sources

- [Bitwarden CLI Compromised in Ongoing Checkmarx Supply Chain Campaign](https://socket.dev/blog/bitwarden-cli-compromised)
- [Malicious Checkmarx Artifacts Found in Official KICS Docker Repository and Code Extensions](https://socket.dev/blog/checkmarx-supply-chain-compromise)
- [TeamPCP Is Systematically Targeting Security Tools Across the OSS Ecosystem](https://socket.dev/blog/teampcp-targeting-security-tools-across-oss-ecosystem)
- [Trivy Under Attack Again: Widespread GitHub Actions Tag Compromise Exposes CI/CD Secrets](https://socket.dev/blog/trivy-under-attack-again-github-actions-compromise)
- [CanisterWorm: npm Publisher Compromise Deploys Backdoor Across 29+ Packages](https://socket.dev/blog/canisterworm-npm-publisher-compromise-deploys-backdoor-across-29-packages)
- [npm package @bitwarden/cli (registry listing)](https://www.npmjs.com/package/@bitwarden/cli)
- [Bitwarden Password Manager (vendor)](https://bitwarden.com/)
- [Checkmarx KICS on Docker Hub](https://hub.docker.com/r/checkmarx/kics)

## Full data

Detection queries (Splunk SPL / Microsoft KQL / Sigma) and IOC values require the Threadlinqs MCP server (Purple tier): https://intel.threadlinqs.com/mcp

Canonical: https://intel.threadlinqs.com/threat/TL-2026-0417
