DEV Community

Juan Torchia
Juan Torchia

Posted on • Originally published at juanchi.dev

Bitwarden CLI compromised: what a supply chain attack on a tool I actually use forces me to audit

Bitwarden CLI compromised: what a supply chain attack on a tool I actually use forces me to audit

The correct solution for protecting your secrets is to stop blindly trusting the password manager you trust the most. I know that sounds weird. Let me explain why the Bitwarden CLI supply chain attack detected by Checkmarx had me auditing my entire CLI tooling infrastructure in a single afternoon.

It was 10pm when I caught the thread on Hacker News: 752 points, top of the day. The title said something about malicious packages in the Bitwarden CLI ecosystem. My first reaction was the average developer reaction: "that sucks, hope it doesn't affect anyone." My second reaction, twenty seconds later, was opening my terminal and typing:

# What do I have installed globally that touches secrets or credentials?
npm list -g --depth=0 | grep -iE "bitwarden|vault|secret|pass|cred|auth|token"
Enter fullscreen mode Exit fullscreen mode

The output hit me like a bucket of cold water. I had four tools with access to sensitive material that I hadn't reviewed in months.

Bitwarden CLI supply chain attack: what Checkmarx actually reported

Checkmarx published that they identified malicious npm packages impersonating legitimate dependencies in the Bitwarden CLI ecosystem — classic typosquatting combined with dependency confusion. The packages had names close enough to the real thing (@bitwarden/cli, bitwarden-cli) to slip into an unsuspecting package.json or a CI script that installs dependencies by name without verified hashes.

This is not a zero-day in Bitwarden the product. They didn't compromise the vault. What they compromised is something more insidious: the supply chain of the tool you use to access the vault.

My point before we go further: this is not Bitwarden's fault. Bitwarden is a solid, open source tool I use with full conviction. The problem is structural and it hits every one of us who builds with CLI tools installed via package managers without enough verification.


The trust surface nobody audits

When I worked at the cyber café at 14, I learned something the industry is still ignoring: the failure point is never the system you think you're protecting — it's the cable nobody checked. When the connection went down at 11pm with a full house, it was never the main router. It was always the switch on the floor below that nobody touched because "it always worked."

A supply chain attack on a CLI tool is exactly that. They don't hack the vault. They hack the executable that opens the vault.

I did this inventory live. I'm reproducing it here because the methodology matters:

# Step 1: list all globally installed CLI tools
npm list -g --depth=0 2>/dev/null
pnpm list -g --depth=0 2>/dev/null

# Step 2: for each one, verify the hash of the installed package
# against the official registry
npm view @bitwarden/cli dist.integrity
# expected output: sha512-[hash]
# compare with what you have installed locally

# Step 3: check what permissions those binaries have
ls -la $(which bw) 2>/dev/null
# if it has SUID or access to the system keychain, that's risky territory
Enter fullscreen mode Exit fullscreen mode

What I found in my own setup: I had bw (Bitwarden's official CLI) installed globally 8 months ago. I also had two third-party tools that use Bitwarden as a backend to inject secrets into deploy scripts. None of the three had their hash verified in my CI pipeline. All three ran with my full user permissions.

That's a trust surface I built myself, without anyone having attacked it yet.


The pattern I already saw with Vercel: they didn't break X, they broke Y

When I wrote about the Vercel breach from April 2026, the conclusion that stung the most was this: they don't break the system you declare as critical. They break the peripheral tool that has lateral access to the critical system.

The supply chain attack on Bitwarden CLI is identical in structure. Nobody is breaking Bitwarden's encryption. They're publishing an npm package with a nearly identical name, waiting for you to install it in a CI/CD pipeline running in production, and from that point on they have access to everything that CI/CD touches — including the secrets Bitwarden was protecting.

The irony is perfect: you installed the password manager to be more secure. The attack uses that trust as the vector.

This connects directly to what I learned building CrabTrap, my LLM-as-a-judge proxy: security is not a state, it's a layer of continuous verification. And that verification has to be in the right place — not after the damage, but at the point of installation.


What I actually changed in my setup after this audit

I'm not going to write a generic "security best practices" tutorial. There are already enough of those and none of them will make you change anything. What I can do is show you exactly what I changed, with real commands.

1. Lockfile with verified integrity for critical CLI tools

# Instead of installing globally without verification:
npm install -g @bitwarden/cli  # ← this doesn't verify anything useful

# Now I use a bootstrap script with an explicit hash:
# bootstrap-tools.sh

BITWARDEN_VERSION="2024.x.x"
BITWARDEN_HASH="sha512-[official-release-hash]"

npm install -g @bitwarden/cli@$BITWARDEN_VERSION
# verify integrity after installing
INSTALLED_HASH=$(npm view @bitwarden/cli@$BITWARDEN_VERSION dist.integrity)

if [ "$INSTALLED_HASH" != "$BITWARDEN_HASH" ]; then
  echo "⚠️ Hash mismatch — installation aborted"
  exit 1
fi

echo "✅ Bitwarden CLI installed and verified"
Enter fullscreen mode Exit fullscreen mode

2. Explicit install scope in CI/CD

# .github/workflows/deploy.yml — excerpt
- name: Install Bitwarden CLI with verification
  run: |
    # install the official scope, not generic names
    npm install @bitwarden/cli@2024.x.x
    # verify the binary comes from where it should
    node -e "
      const pkg = require('@bitwarden/cli/package.json');
      console.log('Installed version:', pkg.version);
      console.log('Repository:', pkg.repository?.url);
      // if the repo isn't github.com/bitwarden, something's wrong
      if (!pkg.repository?.url?.includes('github.com/bitwarden')) {
        console.error('ALERT: unexpected repository');
        process.exit(1);
      }
    "
Enter fullscreen mode Exit fullscreen mode

3. Automated periodic auditing

I added this directly to my Railway pipeline after reading the Checkmarx report. It's simple but it forces someone (me) to review it every week:

# audit-cli-tools.sh — runs on weekly cron
#!/bin/bash

CRITICAL_TOOLS=("@bitwarden/cli" "gh" "railway" "vercel")

for tool in "${CRITICAL_TOOLS[@]}"; do
  echo "🔍 Auditing: $tool"

  # compare installed version with latest on registry
  LOCAL_VERSION=$(npm list -g $tool --depth=0 2>/dev/null | grep $tool | awk -F@ '{print $NF}')
  REGISTRY_VERSION=$(npm view $tool version 2>/dev/null)

  if [ "$LOCAL_VERSION" != "$REGISTRY_VERSION" ]; then
    echo "⚠️  $tool: local=$LOCAL_VERSION, registry=$REGISTRY_VERSION"
  else
    echo "✅ $tool: $LOCAL_VERSION"
  fi
done
Enter fullscreen mode Exit fullscreen mode

The gotchas nobody mentions in supply chain write-ups

I went through a lot of content after the HN thread. Most of it focuses on the attack itself and "keep your dependencies updated." Fine, but that leaves out three things I think matter more:

1. Typosquatting is more effective against CLI tools than against libraries

When you install a library in a project, there's a versioned package.json you review (or should review). When you install a CLI tool, most people copy the command from the docs and never question it again. That habit is exactly what these attacks exploit.

2. Third-party tools that use your password manager are the real risk

The official Bitwarden CLI has a reasonably audited release process. The problem is the wrappers, the integration scripts, the "helpers" you find on GitHub with 40 stars that install @bitwarden/cli as a dependency without a lockfile. I had two of those in my setup. I removed them.

3. The attack surface grows with every agent that has access to secrets

This worries me more than the specific attack. I'm building flows with agents that need access to environment variables and secrets to function. I've written about the non-obvious costs of async agents and about what happens when agents touch production, but the security axis of those flows is something I hadn't resolved properly. An agent that runs arbitrary code and has access to the Bitwarden CLI is an enormous attack surface. LLM-powered security reports won't catch this — it's an architecture problem, not a code problem.

And here's what really unsettles me: if you're building agents that make autonomous decisions — a topic I get into in benchmarks with TPU v8 and the agentic era — every tool that agent can invoke is part of the attack surface. Auditing the agent's code isn't enough. You have to audit everything the agent can execute.


FAQ: Bitwarden CLI supply chain attack and trust surface

Did the attack compromise the Bitwarden vault or my stored passwords?

Not directly. What Checkmarx reported are malicious npm packages impersonating Bitwarden's official CLI. If you installed the legitimate CLI from the official channel (@bitwarden/cli published by the Bitwarden team), your stored passwords are not compromised. The risk is if you installed a package with a similar name published by a malicious actor, which could capture the credentials you use to unlock the vault.

How do I know if I installed the legitimate package or a malicious one?

Check the publisher of the installed package: npm view @bitwarden/cli should show that the maintainer is the official Bitwarden team (you can confirm at npmjs.com/package/@bitwarden/cli). If you installed something with a similar but different name (e.g. bitwarden-cli, bitwarden_cli, @bitwarden/cli-tool), uninstall it and audit what access it had.

Are dependency confusion and typosquatting the same thing?

No, though both appear in this type of attack. Typosquatting is registering a name close to the legitimate one, betting on a typo. Dependency confusion is publishing on npm a package with the same name as a private internal one, exploiting the fact that package managers sometimes prioritize the public registry. Different vectors, similar effect: you install something malicious thinking it's legitimate.

Is Bitwarden CLI safe to use after this?

Yes, with explicit verification. The product itself wasn't compromised. What I changed is the installation process: verify the hash, always install from the official @bitwarden/cli scope, and periodically audit that the version installed in CI matches what the official registry reports.

Does this apply only to npm or also to other ways of installing Bitwarden CLI?

The npm vector is the most relevant for developers. If you install Bitwarden CLI via the official installer from Bitwarden's site, system packages (apt, brew, winget), or download the signed binary directly from GitHub Releases, the risk from this particular attack is very low. The problem is specific to the npm ecosystem and package name confusion.

How do I apply this to other critical CLI tools, not just Bitwarden?

Same principle: for every CLI tool that has access to secrets, credentials, or can execute actions in production — gh, railway, vercel, aws, gcloud — verify you're installing from the correct scope/publisher, that there's a pinned hash or version in your CI scripts, and that you have some alert mechanism when something changes. It's not perfect but it drastically reduces your accidental attack surface.


My final take: the problem isn't Bitwarden, it's you building without a map

We build infrastructure with dozens of CLI tools. Each one has access to something. Most of them we install once, they work, and we forget about them. That's exactly the mental model supply chain attacks exploit: they don't attack the moment you're alert, they attack the moment you stopped looking.

What changed for me that afternoon wasn't the Checkmarx attack itself — it was realizing I had no map of my own trust surface. I didn't know exactly what I had installed, what version it was, or what permissions it ran with. That's a problem regardless of whether anyone is attacking me or not.

I'm not going to stop using Bitwarden CLI. It's still the best option for what I need. But now I install it with a verified hash, audit it weekly in CI, and I removed the third-party wrappers that used it as a dependency without a lockfile.

What CLI tools do you have installed that have access to secrets or production? Do you know exactly what hash they're running? If the answer is "more or less," today is a good day to do the inventory. Run the first command in this post and see what shows up. Then tell me what you found.


This article was originally published on juanchi.dev

Top comments (0)