When Your Password Manager Attacks You: Inside the Bitwarden CLI Supply Chain Compromise
How the @bitwarden/cli npm package was hijacked for 93 minutes on April 22, 2026, subverting trusted publishing to steal AWS, GitHub, and SSH credentials from 334 installs.
PermalinkThe 93-Minute Breach
At 6:15 PM on a Wednesday evening in April 2026, a developer on a platform team runs a routine command: npm install -g @bitwarden/cli. They are setting up credential management for a new CI/CD pipeline. Within three seconds, a script called bw_setup.js silently downloads a runtime, scans their filesystem for every secret it can find -- AWS keys, GitHub tokens, SSH private keys, even their AI assistant's configuration -- encrypts the haul with AES-256-GCM, and ships it to a server impersonating a well-known security company.
The package has valid provenance. The attestation checks out. npm says it is legitimate. It is not.
An attack that targets the software delivery pipeline rather than the final application directly. Instead of exploiting a vulnerability in your code, the attacker compromises a dependency, build tool, or distribution channel that you trust implicitly -- poisoning your software from the inside.
Between 5:57 PM and 7:30 PM ET on April 22, 2026, the malicious @bitwarden/cli@2026.4.0 sat on the npm registry accepting installations [1]. In those 93 minutes, approximately 334 developers installed a password management tool that had been weaponized to steal their secrets [2]. The package attracted roughly 297,738 monthly downloads under normal circumstances -- meaning 250,000+ developers narrowly missed the window [3].
What was stolen from those 334 installs: AWS access keys, Azure service principals, GCP credentials, GitHub personal access tokens, npm publishing tokens, SSH private keys, shell history files, .env files, and -- in a novel twist -- AI tool configurations including .claude.json, .kiro, and Cursor settings [4].
A mechanism where npm packages are published exclusively through CI/CD pipelines (like GitHub Actions) using short-lived OIDC tokens rather than long-lived npm access tokens. The package registry verifies that the publish request comes from an authorized workflow in the source repository, creating a cryptographic chain of trust from source code to published artifact.
The deepest irony: this package used npm's newest and strongest trust mechanism -- trusted publishing via OIDC tokens [4]. The provenance attestation was valid because the build came from Bitwarden's own GitHub Actions workflow. The system worked exactly as designed. The problem was that the build pipeline itself had been compromised, and no downstream verification could detect that.
Trusted publishing guarantees that a package came from the expected build system. It does NOT guarantee that the build system itself is trustworthy. When the pipeline is the attack vector, provenance faithfully attests to a malicious build.
How did the most trusted publishing mechanism in npm's history become the vector for one of its most sophisticated attacks? The answer lies in a seven-year evolutionary arms race.
Historical Origins -- The Ancestry of npm Supply Chain Attacks
Supply chain attacks did not start sophisticated. They started with a typo.
In 2017, an unknown threat actor registered a package called crossenv -- a single missing hyphen away from the popular cross-env build tool [5]. Developers who mistyped the package name during installation silently handed their environment variables to a stranger. It was cheap, effective, and embarrassingly simple.
The crossenv package was detected within days by security researchers who noticed the name similarity. But in those few days, it demonstrated something important: npm's open publishing model -- the same radical openness that enabled JavaScript's explosion -- also enabled trivial abuse.
The npm community adapted. Detection tools began scanning for suspicious near-name packages. The door closed.
The Social Engineering Breakthrough (2018)
Then came event-stream, and everything changed. In November 2018, developer Ayrton Sparling discovered that a Bitcoin-stealing backdoor had been injected into a widely-used package [6]. The attack had not exploited any technical vulnerability. Instead, an attacker using the pseudonym "right9ctrl" had simply asked the package's burned-out maintainer, Dominic Tarr, if they could help maintain it [7].
Dominic Tarr later explained his decision candidly. He had stopped using event-stream years earlier. The burden of maintaining popular open-source software with no compensation drove him to hand off control without due diligence. The community realized: open-source sustainability is a security problem.
Tarr agreed. The attacker added a new dependency called flatmap-stream containing code that specifically targeted the Copay cryptocurrency wallet. The malicious code lay dormant for months before discovery [8].
No security mechanism could have prevented this because it looked like legitimate maintainer succession. The problem was not just technical -- it was human.
The Algorithm Exploits (2021)
In February 2021, security researcher Alex Birsan demonstrated a fundamentally new attack class. He discovered that when companies use private internal package names, an attacker can publish identically-named packages to the public npm registry -- and the build system will fetch the attacker's version due to namespace priority resolution. He breached Apple, Microsoft, PayPal, and dozens of other companies, earning over $130,000 in bug bounties [9].
Birsan earned more in bug bounties from dependency confusion than many npm package maintainers earn in a year of maintaining the packages that millions depend on. The economic asymmetry between attack value and maintenance funding remains one of open source's unsolved problems.
That same year, Codecov revealed that their Bash Uploader script -- used in thousands of CI/CD pipelines -- had been quietly exfiltrating environment variables to an attacker-controlled server since January 31 [10]. This was the first major CI/CD pipeline compromise at scale.
Then in October, ua-parser-js -- one of npm's most downloaded packages -- was hijacked via a compromised maintainer account. Malicious versions containing cryptominers and credential stealers were published directly [11, 12].
In January 2022, Marak Squires -- maintainer of colors.js and faker.js -- deliberately broke his own packages as protest against unpaid open-source labor [13]. While not a traditional attack, it proved that even "trusted" publishers can become vectors when a single person controls what millions depend on.
Each defense closed one door. But each closure revealed the next door was unlocked. The question became: what happens when attackers stop targeting the package and start targeting the pipeline that builds it?
The Evolution -- From Typosquatting to CI/CD Weaponization
The history of npm attacks reads like a predator-prey arms race. Every defense pushes the attacker one trust boundary upstream -- from package names, to registry resolution, to maintainer accounts, to the build system itself.
Diagram source
gantt
title npm Supply Chain Attack Evolution (2017-2026)
dateFormat YYYY
axisFormat %Y
section Generation 1
Typosquatting (crossenv) :2017, 2019
section Generation 2
Dependency Confusion (Birsan) :2021, 2022
section Generation 3
Account Takeover (ua-parser-js) :2021, 2023
section Generation 4
CI/CD Poisoning (tj-actions) :2021, 2025
section Generation 5
Self-Propagating Worm (Shai-Hulud) :2025, 2026 An attack that exploits package manager resolution priority. When an organization uses private package names without namespace scoping, an attacker publishes identically-named packages to the public registry with higher version numbers. Build systems fetch the attacker's public package over the legitimate private one.
Here is how each generation escalated:
| Generation | Attack Vector | Blast Radius | Detection Difficulty | Defense That Stopped It |
|---|---|---|---|---|
| 1: Typosquatting (2017) | Human typos | Individual developers | Low -- name similarity | Automated name scanning |
| 2: Dependency Confusion (2021) | Registry resolution logic | Targeted organizations | Medium -- internal names | Scoped packages, registry config |
| 3: Account Takeover (2021-2023) | Stolen credentials | All package consumers | High -- legitimate identity | MFA mandates, provenance |
| 4: CI/CD Poisoning (2021-2025) | Build pipeline compromise | All downstream consumers | Very high -- valid attestation | SHA pinning, runtime monitoring |
| 5: Self-Propagating Worm (2025-2026) | Automated credential theft + re-publish | Exponential (registry-wide) | Extreme -- self-sustaining | Detection speed + credential ephemerality |
The bridge insight connecting every generation: each defense pushes attackers to target the next trust boundary upstream. Automated name scanning stopped typosquatting. Scoped packages stopped dependency confusion. MFA stopped account takeover. That left one target: the CI/CD pipeline that sits above all these defenses.
Each generation of npm supply chain attack exploits the trust boundary that the previous generation's defense created. When you protect the package name, attackers target the registry. When you protect the registry, they target the maintainer. When you protect the maintainer, they target the build system. The attack surface is not the package -- it is the chain of trust itself.
Generation 4 struck in March 2025 when the widely-used GitHub Action tj-actions/changed-files was compromised [14]. An attacker obtained a Personal Access Token, then retroactively modified all Git tags (v1 through v45.0.7) to point to a malicious commit. Over 23,000 repositories that referenced this action by tag suddenly pulled compromised code that dumped CI runner secrets to workflow logs [15].
The attack proved that mutable Git tags -- the standard way developers reference GitHub Actions -- create a massive attack surface. Any previously-pinned tag reference could be silently redirected.
But Generations 4 and 5 converged in a single attack that combined CI/CD poisoning, trusted publishing abuse, and self-propagation. That attack has a name: Shai-Hulud, The Third Coming.
The Breakthrough -- Shai-Hulud and Self-Propagating Worms
In September 2025, Checkmarx researchers discovered something unprecedented: an npm worm that did not just compromise one package -- it used stolen credentials to automatically infect every other package its victim maintained [16].
"First self-replicating supply chain attack, which uses GitHub Actions to infect repositories that consume any previously-infected package" -- Checkmarx Supply Chain Security [16]
A type of malware that spreads autonomously without further attacker interaction. In the npm context, a self-propagating worm harvests publishing credentials from one victim, then uses those credentials to inject itself into all packages that victim controls -- turning each new victim into a new attack vector in a cascading chain.
The worm was named Shai-Hulud -- the Fremen name for the giant sandworms of Frank Herbert's Dune.
The Shai-Hulud name itself came from Dune. Later TeamPCP infrastructure in the Bitwarden incident used additional Dune-themed terms such as sardaukar, fremen, atreides, and sandworm for fallback exfiltration repositories [2].
Shai-Hulud 1.0 (September 2025)
The first iteration compromised nearly 200 unique packages across roughly 600 infected versions by harvesting npm and GitHub credentials, then automatically republishing infected packages under the victim's own maintainer identity [16, 17]. A separate npmjs[.]help phishing campaign hit the ecosystem days earlier, but Shai-Hulud's propagation mechanism was automated token theft and republishing. Once credentials were harvested, the worm:
- Downloaded, infected, and republished every package the victim could publish
- Used TruffleHog-style credential scanning to find additional tokens
- Exfiltrated data to attacker-controlled GitHub repositories
- Injected malicious GitHub Actions workflows for persistence
Each newly infected package repeated the cycle. One compromised maintainer's packages infected all their consumers' packages -- exponential propagation [18].
Shai-Hulud 2.0 (November 2025)
About ten weeks later, on November 24, 2025, the second iteration hit harder: 796 unique packages compromised, affecting over 20 million weekly downloads [19]. High-profile targets included Zapier, PostHog, and Postman packages [20]. Microsoft later published detection guidance including Defender for Cloud alerts and hunting queries for setup_bun.js and bun_environment.js patterns.
Diagram source
flowchart TD
A[Initial Compromise
Stolen maintainer tokens] --> B[Credential Harvesting
npm tokens, GitHub PATs, SSH keys]
B --> C[Package Infection
Inject malicious postinstall into
all victim-owned packages]
C --> D[New Victims Install
Infected packages]
D --> B
B --> E[GitHub Persistence
Inject malicious workflows
into victim repositories]
E --> F[CI/CD Runners
Harvest ACTIONS_RUNTIME_TOKEN
and runner secrets]
F --> B Shai-Hulud 1.0 and 2.0 were devastating but impersonal -- they hit whatever packages their victims happened to maintain. The third iteration would be different. It would target a specific, high-value package with surgical precision.
Anatomy of the Attack -- Bitwarden CLI @2026.4.0
At 5:57 PM ET on April 22, 2026, npm's registry accepted a new publish of @bitwarden/cli version 2026.4.0. The provenance attestation was valid. The source was Bitwarden's own GitHub Actions workflow. Everything looked legitimate. Everything was compromised.
"The malicious package was briefly distributed through the npm delivery path for @bitwarden/cli@2026.4.0 between 5:57 PM and 7:30 PM (ET) on April 22, 2026" -- Bitwarden Security Team [1]
A cryptographically signed record that links a published npm package to its source repository, build workflow, and commit SHA. Generated during npm publish using Sigstore's Fulcio certificate authority and recorded in the Rekor transparency log. Provenance tells you WHERE a package came from, not WHETHER the source code is safe.
Phase 1: Initial Access
Two different analyses describe the initial access from complementary angles. Endor Labs attributes the CI/CD compromise to a poisoned third-party GitHub Action -- checkmarx/ast-github-action -- which had been compromised as part of the broader TeamPCP campaign and was present in Bitwarden's CI/CD workflow [3]. StepSecurity's deeper analysis reveals that a Bitwarden engineer's GitHub account was compromised, allowing the attacker to create a new branch, stage a prebuilt malicious tarball, and rewrite the publish-cli.yml workflow to exchange a GitHub Actions OIDC token for an npm auth token [4].
A mechanism where GitHub Actions workflows request short-lived tokens from an OpenID Connect identity provider. For npm trusted publishing, the workflow proves its identity to npm's registry without storing any long-lived secrets. The registry trusts the token because it trusts GitHub's OIDC provider -- creating a chain of trust that breaks if the workflow itself is compromised.
When Bitwarden's CI/CD pipeline ran its publish workflow, the attacker's modifications injected two files into the build: bw_setup.js and bw1.js [2]. Because the publish used OIDC trusted publishing, the resulting package carried valid provenance -- npm had no reason to reject it.
"First confirmed supply chain attack where npm's OIDC Trusted Publishing was used to publish a compromised package" -- StepSecurity [4]
Phase 2: Payload Execution
When a victim ran npm install -g @bitwarden/cli@2026.4.0, the preinstall hook triggered bw_setup.js, which immediately downloaded the Bun runtime for fast JavaScript execution [2]. Then bw1.js executed three parallel collector routines:
Diagram source
sequenceDiagram
participant Dev as Developer
participant npm as npm Registry
participant BW as @bitwarden/cli@2026.4.0
participant Bun as Bun Runtime
participant C2 as audit.checkmarx[.]cx
participant GH as GitHub Repos (fallback)
Dev->>npm: npm install -g @bitwarden/cli
npm->>Dev: Package with valid provenance
Dev->>BW: preinstall hook triggers bw_setup.js
BW->>Bun: Download Bun runtime
Bun->>BW: Ready
BW->>BW: Execute bw1.js collectors
Note over BW: Filesystem: SSH keys, .npmrc, .env, AI configs
Note over BW: Environment: shell history, cloud creds
Note over BW: CI Runner: ACTIONS_RUNTIME_TOKEN, secrets
BW->>BW: AES-256-GCM encrypt collected data
BW->>C2: POST encrypted payload
alt Primary C2 fails
BW->>GH: Commit to Dune-themed repos
end Filesystem collector: Scanned for SSH keys (~/.ssh/), npm tokens (~/.npmrc), environment files (.env), cloud provider credential files, and -- notably -- AI tool configurations including .claude.json, .kiro, and Cursor settings [22].
The targeting of AI tool configurations (.claude.json, .kiro, Cursor) is novel -- it suggests awareness that developers increasingly store API keys and authentication tokens in AI assistant configs. As AI-assisted development grows, these configs become high-value targets containing keys to multiple services.
Shell and environment collector: Harvested shell history files (which often contain pasted tokens and passwords), environment variables, and cloud provider credentials for AWS, Azure, and GCP [2].
GitHub Actions runner collector: When running on a CI/CD runner, harvested the ACTIONS_RUNTIME_TOKEN, runner secrets, and workflow-level variables [4].
Phase 3: Exfiltration and Self-Propagation
All collected data was encrypted with AES-256-GCM and POSTed to audit.checkmarx[.]cx -- a domain impersonating the legitimate security company Checkmarx [2]. If the primary command-and-control server was unreachable, the malware fell back to committing encrypted data to GitHub repositories with Dune-themed names (sardaukar, fremen, atreides, sandworm) using stolen GitHub tokens.
The malware includes a locale check that skips execution if the system has Russian language configured -- a common tactic by Russian-origin threat actors to avoid domestic prosecution under Russian law [23].
Stolen GitHub tokens were then used to inject malicious workflows into victim repositories, creating persistence and enabling further propagation. This self-propagation mechanism -- the hallmark of the Shai-Hulud campaign -- meant each compromised developer potentially infected their entire organization's codebase.
Detection and Takedown
The attack lasted 93 minutes. Socket, JFrog, and StepSecurity independently detected the compromise through behavioral analysis of the published package and runtime monitoring [24]. The malicious version was unpublished, and Bitwarden issued their official statement the following day confirming no vault data or production systems were affected [1].
The attack brilliantly exploited trust -- but could existing defenses have caught it? The answer reveals uncomfortable gaps in current security tooling.
State of the Art -- Defenses and Their Limits
Six major approaches exist to defend against supply chain attacks. Against the Bitwarden compromise, most of them failed -- not because they are bad tools, but because they were designed for a previous generation of attacks.
npm Provenance and SLSA
A security framework that defines increasing levels of supply chain integrity. The Build Track specifies four levels: L0 (no requirements), L1 (provenance exists), L2 (signed provenance from a hosted build platform), and L3 (a hardened build platform that resists tampering during the build). SLSA addresses build integrity but not source code safety [25].
npm provenance creates a cryptographic chain from source repository to published package via Sigstore's transparency log. Consumers verify via npm audit signatures that a package was built from the expected source by the expected workflow.
Against the Bitwarden attack: FAILED. Provenance was bypassed because the CI/CD pipeline itself was compromised. The attestation correctly recorded that the package came from Bitwarden's GitHub Actions workflow and their source repository. The provenance was technically valid -- it just attested to a malicious build [4].
Behavioral Analysis (Socket)
Socket performs static and dynamic analysis of package behavior at publish time -- scanning for risky API usage, unexpected network connections, obfuscated code, and anomalous file system access.
Against the Bitwarden attack: WOULD DETECT. The malicious bw_setup.js downloading Bun, scanning for credentials, and making outbound POST requests to audit.checkmarx[.]cx would trigger multiple behavioral alerts [24].
CI/CD Runtime Monitoring (StepSecurity Harden-Runner)
Harden-Runner monitors GitHub Actions workflows at runtime -- tracking outbound network connections, process execution, and file access against configured allow-lists.
Against the Bitwarden attack: WOULD DETECT. The poisoned action making unauthorized outbound connections to attacker infrastructure would violate network policies. StepSecurity was among the first to detect and report the compromise [4].
Lockfile Integrity
npm ci enforces strict lockfile adherence with SHA-512 hash verification. The --ignore-scripts flag prevents execution of install hooks.
Against the Bitwarden attack: PARTIAL. For consumers who pinned the exact previous version, their lockfile hash would not match the new malicious version. However, anyone running npm update or installing fresh would get the compromised version. The --ignore-scripts flag would have prevented payload execution entirely -- but breaks many legitimate packages that need native compilation.
SCA Tools (JFrog, Snyk)
Software Composition Analysis tools match packages against known-malicious databases and real-time threat feeds.
Against the Bitwarden attack: DETECTED within 90 minutes. JFrog's real-time analysis identified the malicious payload during the attack window, contributing to the 93-minute takedown [2].
GitHub Actions SHA Pinning
Pinning actions by commit SHA rather than mutable tag prevents tag-swapping attacks.
Against the Bitwarden attack: COMPLEX. Under the Endor Labs narrative (poisoned third-party checkmarx/ast-github-action), SHA pinning of that action WOULD have prevented the initial compromise. Under the StepSecurity narrative (direct engineer account compromise allowing workflow rewrite), SHA pinning would be moot because the attacker could modify the workflow file itself [14]. Either way, SHA pinning remains critical defense against the broader class of tag-swapping attacks demonstrated by tj-actions.
Diagram source
flowchart LR
subgraph Attacks
T[Typosquatting]
DC[Dependency Confusion]
AT[Account Takeover]
CP[CI/CD Poisoning]
SW[Self-Propagating Worm]
end
subgraph Defenses
NS[Name Scanning]
LF[Lockfile + Scoped Pkgs]
MFA[MFA + Provenance]
SHA[SHA Pinning]
BA[Behavioral Analysis]
RM[Runtime Monitoring]
end
NS -.->|blocks| T
LF -.->|blocks| DC
MFA -.->|blocks| AT
SHA -.->|partially blocks| CP
BA -.->|detects| CP
BA -.->|detects| SW
RM -.->|detects| CP
RM -.->|detects| SW Even layered defenses have theoretical limits. Some of those limits are mathematical, not merely practical.
Theoretical Limits -- Why Perfect Prevention Is Impossible
Here is an uncomfortable truth from computer science: perfect malware detection is provably impossible.
A 1953 result in computability theory proving that no algorithm can decide all non-trivial semantic properties of programs. Applied to security: no static analysis tool can determine with certainty whether an arbitrary program will exhibit malicious behavior for all possible inputs. Perfect malware detection is undecidable -- there will always be programs that evade any fixed detection strategy.
Rice's Theorem (1953) guarantees that no algorithm can determine whether an arbitrary program exhibits malicious behavior. This is not a limitation of current tools -- it is a mathematical impossibility. Any behavioral detection system must either accept false negatives (missing some malware) or false positives (flagging safe programs).
The Trusting Trust Problem
In 1984, Ken Thompson -- co-creator of Unix -- delivered his Turing Award lecture with a devastating demonstration [26]. He showed that a compiler could be modified to inject backdoors into programs it compiled, and then modified to inject the backdoor into itself when recompiled from clean source.
Thompson's demonstration revealed that you cannot fully trust any software by examining its source code alone -- the compiler that builds it could be compromised, and the compiler that builds the compiler, ad infinitum. He concluded: "You can't trust code that you did not totally create yourself." The Bitwarden attack is the modern manifestation of Thompson's insight applied to CI/CD pipelines.
The implication is direct: the CI/CD pipeline that builds your package is itself software, built by other software, running on systems maintained by other systems. The verification chain is infinitely recursive. You cannot fully verify the tools that verify the tools.
The Provenance Paradox
Provenance attestation guarantees one thing: this package was built from this source by this system. It does NOT guarantee that the source code is safe, that the build system is trustworthy, or that no intermediate step was compromised.
When the source repository itself contains malicious code injected via a compromised CI/CD pipeline (as in the Bitwarden attack), provenance faithfully attests to the malicious build. The attestation is correct -- it just does not mean what we assumed it meant.
The npm registry hosts millions of packages. Even if 99.99% are safe, that leaves hundreds of potential attack vectors. At current growth rates, the attack surface expands faster than any detection system can keep pace.
What This Means for Defenders
The practical consequence: security cannot be achieved through any single verification layer. The Bitwarden attack exploited the gap between what provenance proves (build integrity) and what developers assume it proves (code safety). Closing that gap requires defense in depth -- multiple independent detection mechanisms that each catch what the others miss.
If perfection is impossible, what problems are worth solving next?
Open Problems -- The Research Frontier
The Bitwarden attack exposed five unsolved problems that no current tool adequately addresses.
1. Detecting compromised first-party CI/CD pipelines before artifact publication.
When a poisoned GitHub Action injects malicious code during the build, the resulting package has valid provenance. Current tools can only detect this after publication -- by analyzing the published artifact's behavior. The gap between "build starts" and "malicious artifact reaches consumers" is the critical window.
Emerging approaches include reproducible builds (where independent rebuilders verify that source produces identical artifacts), workflow diffing (alerting when publish workflows change between runs), and multi-party signing (requiring multiple independent build systems to attest before publication). A stronger Actions-specific SLSA profile would require the build platform to verify that no workflow step injected unexpected files -- but defining "unexpected" without breaking legitimate build customization remains unsolved.
2. Real-time malware detection at registry scale.
The Bitwarden attack lasted 93 minutes. JFrog and Socket detected it within that window -- impressive, but 334 developers still installed it. True protection requires detection before the first consumer downloads a compromised package. npm processes tens of thousands of new package versions daily, demanding near-instant behavioral analysis at enormous scale.
Current approaches include OpenSSF Package Analysis (which runs packages in sandboxed VMs and monitors syscalls), Socket's static heuristics (sub-second but limited to known patterns), and ML-based anomaly detection (identifying packages whose behavior diverges from their previous versions). The latency target is under 60 seconds from publish to verdict -- fast enough that even automated CI pipelines would not install before scanning completes.
3. Preventing credential propagation in self-replicating worms.
Shai-Hulud's self-propagation relies on harvesting long-lived credentials (npm tokens, GitHub PATs) from developer environments. Short-lived OIDC tokens help, but developer workstations still contain persistent credentials by necessity.
The open question: can we architect a development workflow where no single compromised machine provides enough credentials to propagate further? Proposals include publish rate-limiting (flagging accounts that suddenly publish dozens of packages), cooling-off periods for new versions of popular packages, and anomaly detection on publish patterns -- distinguishing a legitimate monorepo release (publishing 20 related packages at once) from worm-driven mass publication.
4. Balancing developer velocity with install-time security.
The --ignore-scripts flag would have prevented this attack entirely by blocking the preinstall hook. But many legitimate packages rely on install scripts for native compilation (node-gyp), platform-specific binary downloads, and post-install configuration. A blanket ban breaks real workflows.
The unsolved problem is granular script authorization -- allowing known-safe hooks while blocking unknown ones. Deno's explicit permission model (--allow-net, --allow-read) offers inspiration: what if npm install scripts declared their required capabilities (network access, file paths, environment variables) and the package manager enforced those declarations? WASI-based isolation could sandbox install scripts with fine-grained capability restrictions, but the migration cost for existing packages is enormous.
5. AI-generated code introducing supply chain blind spots.
The attack specifically targeted AI tool configurations. As AI agents increasingly manage dependencies, write code, and execute builds, they become a new trust boundary. An AI agent that trusts its own configuration files creates a recursive vulnerability -- compromise the config, compromise the agent, compromise everything the agent touches.
These problems are not merely academic -- they represent the next battleground. But what can you do today, before they are solved?
Practical Guide -- Defending Your Pipeline Today
Theory and open problems aside, here are the concrete steps you can take today to avoid being the next victim.
Immediate Actions (Today)
Pin GitHub Actions by commit SHA, not tag.
# BAD: mutable tag can be redirected
uses: actions/checkout@v4
# GOOD: immutable commit SHA
uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29
This single change would have prevented the tj-actions attack and would make CI/CD pipeline poisoning significantly harder [14].
Use npm ci --ignore-scripts in CI pipelines. Then allowlist specific scripts explicitly in your .npmrc:
# .npmrc
ignore-scripts=true
# Explicitly allow known-safe scripts
script-shell=/bin/bash
Run npm audit signatures to verify that installed packages have valid provenance attestations from their expected source repositories.
Enable branch-level OIDC token restrictions in your repository settings to prevent publish tokens from being minted on non-main branches.
Short-Term Actions (This Quarter)
- Adopt Socket or equivalent behavioral scanning for your dependency installs
- Deploy StepSecurity Harden-Runner in audit mode on all CI/CD workflows
- Implement automated secret rotation -- no credential should live longer than 24 hours in CI
- Audit all third-party GitHub Actions in your workflows against their source repositories
Medium-Term Actions (This Year)
- Achieve SLSA Build Level 3 for any packages you publish
- Replace all long-lived npm tokens with OIDC-based trusted publishing
- Restrict GitHub Action permissions to absolute minimum required per job
- Implement environment-based deployment gates with required reviewer approval
Incident response if you installed @bitwarden/cli@2026.4.0
- Rotate ALL credentials immediately: AWS access keys, Azure service principals, GCP service accounts, GitHub PATs, npm tokens, SSH keys
- Check for unauthorized workflows: Search all your repositories for workflow files you did not create
- Search for artifacts: Look for
bw_setup.js,bw1.js, or network connections toaudit.checkmarx[.]cxin your logs - Review GitHub audit log: Check for unexpected repository creation, especially repos with Dune-themed names
- Scan AI tool configs: Check
.claude.json,.kiro, and Cursor settings for modifications - Notify your security team: This is a credential compromise -- treat it as a full-blown incident requiring forensic investigation
// Indicators of Compromise (IOC) checker for Bitwarden CLI attack
const fs = require('fs');
const path = require('path');
const os = require('os');
const iocs = {
files: ['bw_setup.js', 'bw1.js'],
domains: ['audit.checkmarx.cx'],
processes: ['bun_environment.js', 'setup_bun.js'],
repos: ['sardaukar', 'fremen', 'atreides', 'sandworm']
};
console.log('=== Bitwarden CLI IOC Scanner ===\n');
// Check for malicious files in common locations
const searchDirs = [
path.join(os.homedir(), '.npm'),
path.join(os.homedir(), 'node_modules'),
'/tmp'
];
let found = false;
for (const dir of searchDirs) {
for (const file of iocs.files) {
const filePath = path.join(dir, file);
if (fs.existsSync(filePath)) {
console.log('[!] FOUND malicious file: ' + filePath);
found = true;
}
}
}
// Check shell history for C2 domain
const historyFiles = ['.bash_history', '.zsh_history'];
for (const hist of historyFiles) {
const histPath = path.join(os.homedir(), hist);
if (fs.existsSync(histPath)) {
const content = fs.readFileSync(histPath, 'utf8');
for (const domain of iocs.domains) {
if (content.includes(domain)) {
console.log('[!] C2 domain found in ' + hist);
found = true;
}
}
}
}
if (!found) {
console.log('[OK] No indicators of compromise detected.');
console.log(' Note: This checks common locations only.');
console.log(' A full forensic scan may still be warranted.');
} Press Run to execute.
Frequently Asked Questions
Common questions about the Bitwarden CLI supply chain attack
I use Bitwarden but not the CLI -- am I affected?
No. The attack only affected the npm package @bitwarden/cli version 2026.4.0, distributed exclusively through the npm registry. The Bitwarden browser extensions, desktop applications, mobile apps, and web vault were not affected. No password vault data was compromised -- only the npm distribution path for the CLI tool was poisoned during the 93-minute window [1].
Were password vaults compromised?
No. Bitwarden confirmed that no vault data, production systems, or cloud infrastructure was accessed [1]. The malicious package targeted developer credentials (AWS, GitHub, npm tokens, SSH keys) on the machines where it was installed -- it did not interact with or access any Bitwarden vault data.
Does npm provenance prevent this kind of attack?
No. Provenance guarantees origin, not safety. When the CI/CD pipeline itself is compromised, the attestation is technically valid for a malicious build. See the analysis in "State of the Art" and "Theoretical Limits" for a full explanation of why provenance alone cannot prevent pipeline-level attacks [4].
Should I stop using npm?
No. npm remains the standard JavaScript package manager with strong security investments. The correct response is defense in depth: pin Actions by SHA, use lockfiles with npm ci, run behavioral analysis tools like Socket, and monitor your CI/CD runtime with tools like Harden-Runner. No package registry is immune to supply chain attacks -- the defenses described in this article apply to PyPI, RubyGems, and other registries too.
Is this related to the real Checkmarx security company?
The domain audit.checkmarx[.]cx was a deliberate impersonation of the legitimate Checkmarx application security company. The real Checkmarx's GitHub Action (checkmarx/ast-github-action) was compromised as part of the attack, but Checkmarx (the company) was a victim -- not a participant. The threat actor exploited both the action and the brand association to make exfiltration traffic appear legitimate.
How do I know if my CI/CD pipeline is compromised?
Look for: unexpected outbound network connections during builds (use Harden-Runner), new files appearing in your build artifacts that are not in your source repository, workflow runs that take significantly longer than usual, and unauthorized changes to your workflow files. Run npm audit signatures on your published packages and verify the provenance matches your expected build system. Monitor your GitHub audit log for unexpected token usage.
What is the connection between this attack and Dune?
The threat actor group TeamPCP named their npm worm campaign "Shai-Hulud" after the giant sandworms in Frank Herbert's science fiction novel Dune. The data exfiltration repositories used Dune-themed names (sardaukar, fremen, atreides, sandworm). The Bitwarden CLI attack was internally designated "Shai-Hulud: The Third Coming" -- the third major iteration of this self-propagating campaign, following the original September 2025 and November 2025 waves [2].
The Trust Paradox
Software supply chains are built on trust. Every npm install is an act of faith -- faith that the package name resolves correctly, that the maintainer is who they claim to be, that the build system executed faithfully, that the registry served what was published, that no step in the chain was silently subverted.
The Bitwarden attack revealed the recursive nature of this trust:
Diagram source
flowchart TD
A[You trust packages] --> B[Built by pipelines]
B --> C[Using GitHub Actions]
C --> D[Maintained by developers]
D --> E[With credentials]
E --> F[Stored in systems]
F --> G[Protected by other packages]
G --> A The Bitwarden attack struck at the credentials level -- proving that when any single link in this circular chain breaks, the entire chain fails silently. The provenance was valid. The signatures checked out. The trust system confirmed what the trust system had been told.
The 334 developers who installed that package were not victims of carelessness. They ran the official package name from the official registry with official attestation. They did everything right by every standard that existed. The system -- not the developers -- failed them.
The way forward is not defense in trust. It is defense in depth: multiple independent verification layers, each assuming every other layer might be compromised. Behavioral analysis that does not trust provenance. Runtime monitoring that does not trust behavioral analysis. Human review that does not trust automated scanning. Redundancy, skepticism, and speed.
The fundamental lesson of the Bitwarden CLI attack is not "trusted publishing failed" -- it is that trust itself is the wrong foundation for security. Every verification mechanism must assume that every other verification mechanism might be compromised. Defense in depth is not a luxury -- it is the only architecture that survives a world where the tools that protect you can be turned against you.
The next Shai-Hulud is already being planned. Its authors watched how this attack was detected in 93 minutes and are working to reduce their observable footprint. The question is not whether the next attack will come -- it is whether your defenses will catch it in the first seconds, not the first hour.
Study guide
Key terms
- Supply chain attack
- Attack targeting the software delivery pipeline rather than the final application
- Trusted publishing
- OIDC-based npm publishing where packages are published exclusively through verified CI/CD pipelines
- SLSA
- Supply-chain Levels for Software Artifacts -- framework defining build integrity levels L0-L3
- Provenance attestation
- Cryptographically signed record linking a published package to its source and build system
- Dependency confusion
- Attack exploiting package manager resolution priority between public and private registries
- Self-propagating worm
- Malware that spreads autonomously by harvesting credentials and infecting other packages
- GitHub Actions OIDC
- Short-lived token mechanism allowing workflows to authenticate without stored secrets
- Rice's Theorem
- Proof that no algorithm can decide all non-trivial semantic properties of programs
References
- (2026). Bitwarden Statement on Checkmarx Supply Chain Incident. https://community.bitwarden.com/t/bitwarden-statement-on-checkmarx-supply-chain-incident/96127 - Official Bitwarden incident disclosure with timeline and remediation steps ↩
- (2026). TeamPCP Campaign Spreads to npm via a Hijacked Bitwarden CLI. https://research.jfrog.com/post/bitwarden-cli-hijack/ - Technical payload analysis including bw_setup.js, exfiltration mechanism, and Dune-themed infrastructure ↩
- (2026). Shai-Hulud: The Third Coming -- Inside the Bitwarden CLI 2026.4.0 Supply Chain Attack. https://www.endorlabs.com/learn/shai-hulud-the-third-coming----inside-the-bitwarden-cli-2026-4-0-supply-chain-attack - Endor Labs technical breakdown including 297,738 monthly downloads exposure ↩
- (2026). Bitwarden CLI Hijacked on npm: Bun-Staged Credential Stealer Targets Developers, GitHub Actions and AI Tools. https://www.stepsecurity.io/blog/bitwarden-cli-hijacked-on-npm-bun-staged-credential-stealer-targets-developers-github-actions-and-ai-tools - First confirmed attack subverting npm OIDC trusted publishing ↩
- (2017). crossenv malware on the npm registry. https://blog.npmjs.org/post/163723642530/crossenv-malware-on-the-npm-registry - npm official advisory on crossenv typosquatting attack exfiltrating environment variables ↩
- (2018). I dont know what to say - event-stream issue #116. https://github.com/dominictarr/event-stream/issues/116 - Original disclosure of flatmap-stream backdoor in event-stream package ↩
- (2018). A Post-Mortem of the Malicious event-stream Backdoor. https://snyk.io/blog/a-post-mortem-of-the-malicious-event-stream-backdoor/ - Detailed analysis of event-stream/flatmap-stream Copay wallet targeting ↩
- (2018). Details about the event-stream incident. https://blog.npmjs.org/post/180565383195/details-about-the-event-stream-incident - Official npm post-mortem of event-stream social engineering compromise ↩
- (2021). Researcher hacks over 35 tech firms in novel supply chain attack. https://www.bleepingcomputer.com/news/security/researcher-hacks-over-35-tech-firms-in-novel-supply-chain-attack/ - Coverage of Alex Birsan dependency confusion research breaching Apple, Microsoft, PayPal ↩
- (2021). Post-Mortem / Root Cause Analysis (April 2021). https://about.codecov.io/apr-2021-post-mortem/ - Codecov Bash Uploader CI/CD compromise affecting thousands of organizations ↩
- (2021). Embedded malware in ua-parser-js (GHSA-pjwm-rvh2-c87w). https://github.com/advisories/GHSA-pjwm-rvh2-c87w - Advisory for ua-parser-js versions 0.7.29, 0.8.0, 1.0.0 containing credential stealer ↩
- (2021). Malware Discovered in Popular NPM Package ua-parser-js. https://www.cisa.gov/news-events/alerts/2021/10/22/malware-discovered-popular-npm-package-ua-parser-js - CISA alert for ua-parser-js credential-harvesting malware ↩
- (2022). colors.js infinite loop issue. https://github.com/Marak/colors.js/issues/285 - Protestware incident demonstrating single-point-of-failure governance risk ↩
- (2025). Supply Chain Compromise of Third-Party tj-actions/changed-files (CVE-2025-30066). https://www.cisa.gov/news-events/alerts/2025/03/18/supply-chain-compromise-third-party-tj-actionschanged-files-cve-2025-30066-and-reviewdogaction - CISA advisory on tj-actions GitHub Action compromise affecting 23,000 repositories ↩
- (2025). GitHub Action tj-actions/changed-files supply chain attack (CVE-2025-30066). https://www.wiz.io/blog/github-action-tj-actions-changed-files-supply-chain-attack-cve-2025-30066 - Wiz analysis of tj-actions PAT compromise and tag manipulation ↩
- (2025). NPM Hit By Shai-Hulud, The Self-Replicating Supply Chain Attack. https://checkmarx.com/zero-post/npm-hit-by-shai-hulud-the-self-replicating-supply-chain-attack/ - Original Shai-Hulud 1.0 discovery report documenting self-propagating npm worm ↩
- (2025). Self-Replicating Worm Hits 180+ Software Packages. https://krebsonsecurity.com/2025/09/self-replicating-worm-hits-180-software-packages/ - Krebs on Security coverage of first Shai-Hulud worm outbreak ↩
- (2025). Shai-Hulud npm attack: What you need to know. https://www.reversinglabs.com/blog/shai-hulud-worm-npm - ReversingLabs analysis of first self-replicating npm worm including credential cascade mechanism ↩
- (2025). Shai-Hulud 2.0 npm worm. https://securitylabs.datadoghq.com/articles/shai-hulud-2.0-npm-worm/ - Datadog analysis of Shai-Hulud 2.0 affecting 796 packages and 20M+ weekly downloads ↩
- (2025). Shai-Hulud 2.0: Guidance for detecting, investigating, and defending against the supply chain attack. https://www.microsoft.com/en-us/security/blog/2025/12/09/shai-hulud-2-0-guidance-for-detecting-investigating-and-defending-against-the-supply-chain-attack/ - Microsoft detection guidance for Shai-Hulud 2.0 targeting enterprise environments ↩
- (2026). Cyber Intel Brief: Bitwarden CLI Backdoored via Compromised CI/CD Pipeline. https://www.dataminr.com/resources/intel-brief/cyber-intel-brief-bitwarden-cli-backdoored-via-compromised-ci-cd-pipeline-active-npm-supply-chain-campaign-classification/ - Threat intelligence linking TeamPCP to Vect RaaS operation ↩
- (2026). Bitwarden CLI Impersonation Attack Steals Cloud Credentials and Spreads. https://www.paloaltonetworks.com/blog/cloud-security/bitwardencli-supply-chain-attack/ - Palo Alto analysis of SSH key, npm token, and AI config theft ↩
- (2026). Shai-Hulud Bitwarden CLI Supply Chain Attack. https://www.ox.security/blog/shai-hulud-bitwarden-cli-supply-chain-attack/ - OX Security analysis including Russian locale kill switch and real user data leaked ↩
- (2026). Bitwarden CLI npm package compromised to steal developer credentials. https://www.bleepingcomputer.com/news/security/bitwarden-cli-npm-package-compromised-to-steal-developer-credentials/ - BleepingComputer coverage confirming 93-minute window and Socket/JFrog detection ↩
- (2023). SLSA Specification v1.0 - Levels. https://slsa.dev/spec/v1.0/levels - SLSA Build Track levels L0-L3 defining supply chain integrity guarantees ↩
- (1984). Reflections on Trusting Trust. https://www.cs.umass.edu/~emery/classes/cmpsci691st/readings/Sec/Reflections-on-Trusting-Trust.pdf - Turing Award lecture demonstrating undetectable compiler backdoors ↩
- (2026). Bitwarden CLI Compromised in Ongoing Checkmarx Supply Chain Campaign. https://thehackernews.com/2026/04/bitwarden-cli-compromised-in-ongoing.html - News coverage citing Socket, JFrog, and StepSecurity detection ↩
- (2025). ctrl-tinycolor and 40+ npm packages compromised. https://www.stepsecurity.io/blog/ctrl-tinycolor-and-40-npm-packages-compromised - StepSecurity detection of Shai-Hulud self-propagating mechanism in popular packages ↩
- (2026). Monitoring npm Supply Chain Attacks. https://unit42.paloaltonetworks.com/monitoring-npm-supply-chain-attacks/ - Unit 42 npm threat environment analysis documenting wormable propagation ↩