alexi.sh
privacy-tooling

Password managers for engineers: Bitwarden CLI vs 1Password CLI vs pass vs gopass 2026

PrivSec Lab··16 min read
Developer terminal session with green-on-dark code output on a mechanical keyboard

PrivSec Lab deep-dive comparing Bitwarden CLI, 1Password CLI, pass, and gopass for developers in 2026. Encryption specs, CI/CD integration, SSH agent, team workflows, and pricing.

Table of Contents

Why CLI matters for engineers

A GUI password manager is a convenience layer. A CLI password manager is infrastructure. The difference becomes obvious the moment you need a secret inside a shell script, a CI/CD pipeline, a Docker build, a Kubernetes init container, or a cron job that runs at 3 AM without a logged-in user anywhere in the chain.

The four workflows that expose this gap are recurring enough to be worth naming explicitly.

Scripting and automation. Shell scripts that call authenticated APIs, database migrations, deployment scripts that rotate TLS certificates — all of them need credentials at runtime. The pattern of hardcoding a secret in a script or environment file is still how most teams start, and it is also how most teams get their first breach. A CLI password manager breaks that pattern cleanly: the credential lives in the vault and is retrieved, used, and discarded in one command invocation.

Secrets rotation. Compliance frameworks (SOC 2, ISO 27001, GDPR operational controls) increasingly require credential rotation on a fixed schedule — 90-day API keys, 30-day database passwords in some environments. Doing this manually is error-prone and slow. A CLI tool wired to a rotation script makes this mechanical: retrieve old secret, call the service API to rotate, write new secret back to vault, update downstream consumers via environment variable injection.

CI/CD secrets injection. The pattern that has become standard in 2026: no secrets in environment variable settings in your CI dashboard. Instead, a short-lived session token authenticates the pipeline to the vault, secrets are fetched at job start, injected into the subprocess environment, and the session expires. This is what bw run, op run, and gopass template rendering enable.

SSH key management. Private SSH keys are credentials. Storing them as plain files on developer machines is the equivalent of a plaintext password. All four tools in this comparison can act as an encrypted store for SSH keys; two of them expose a native SSH agent socket that handles sign operations without ever placing the decrypted key on disk.

The four tools we compare sit in two categories. Bitwarden CLI and 1Password CLI are frontends to cloud-synced vault services with commercial infrastructure behind them. pass and gopass are local-first tools built on GnuPG encryption and git synchronization, with no mandatory cloud component. The trade-offs between those two models — operational simplicity versus trust model — are the axis around which most team decisions turn.

Bitwarden CLI deep-dive

Bitwarden is an open-source password manager with a self-hostable server (Vaultwarden is the community fork, Bitwarden's official server is also open-source). The CLI, bw, is a Node.js binary that ships as a single compiled executable for Linux, macOS, and Windows.

Authentication and vault unlock. Two authentication paths exist. Interactive login with bw login prompts for email, master password, and 2FA token. API key login with bw login --apikey uses BW_CLIENTID and BW_CLIENTSECRET environment variables — this is the correct path for CI/CD pipelines. After authentication, vault unlock is a separate step: bw unlock with BW_PASSWORD set returns a session token. Store the session token in BW_SESSION for the duration of the job.

export BW_SESSION=$(bw unlock --passwordenv BW_PASSWORD --raw)
bw get password "production/postgres"

The session token is a local AES-256 key that decrypts the cached encrypted vault blob. It is short-lived by default (15 minutes of inactivity) and does not leave the machine.

Sync model. The vault is cached locally as an encrypted blob after bw sync. In CI environments, always run bw sync at the start of a job to ensure the local cache matches the server. The sync is a full pull: no partial sync is available, which means the operation is O(vault size). For vaults under 10,000 items, sync latency is under 2 seconds.

Encryption specification. Bitwarden encrypts vault data with AES-256-CBC with a random IV per field. The vault key is derived from the master password using Argon2id (64 MB memory, 3 iterations, 4 threads). The stretched key never leaves the client. All cryptographic operations happen locally; the server stores only the ciphertext. The source code for both the client and server is on GitHub and has been audited by third parties — the most recent audit by Cure53 was published in March 2025.

Environment variable patterns. For application secrets, Bitwarden supports loading credentials directly into subprocess environments:

bw get notes "app/env-vars" | source /dev/stdin
# or use bw run (wrapper):
bw run -- ./my-script.sh

The bw run command is not yet feature-complete compared to op run, but handles the most common cases.

Pricing. Free tier: unlimited passwords, no item sharing, no 2FA recovery, no TOTP. Individual plan: $10/year — adds TOTP support, encrypted attachments, emergency access. Teams plan: $4/user/month — adds shared organization vaults, group management, admin console, event logs, API access. The self-hosted option is available on all paid plans at no additional cost: deploy Bitwarden server on your own infrastructure and the CLI connects to it.

1Password CLI deep-dive

1Password is a closed-source, commercial password manager. The CLI, op, is a Go binary distributed through the 1Password package repositories and Homebrew. It is the most feature-complete of the four tools from a CI/CD and developer workflow perspective.

Authentication and service accounts. 1Password CLI 2.x introduced service accounts specifically for non-interactive use. A service account has a token (OP_SERVICE_ACCOUNT_TOKEN) that grants read or read-write access to specific vaults. There is no master password in the loop. This is the correct model for CI/CD pipelines, shared secrets in containers, and any automated system that needs long-lived credential access.

export OP_SERVICE_ACCOUNT_TOKEN="ops_..."
op read "op://DevVault/postgres/password"

SSH agent integration. This is the feature that separates 1Password from the other three tools for individual developer workflows. The 1Password app exposes an SSH agent socket (/tmp/1password-ssh-agent.sock). Add IdentityAgent to your ~/.ssh/config and your SSH keys are signed by the agent without the private key ever touching the filesystem in plaintext. Combined with biometric unlock (Touch ID on macOS, Windows Hello), this is the most ergonomic SSH key workflow available today.

Host *
  IdentityAgent "~/Library/Group Containers/2BUA8C4S2C.com.1password/t/agent.sock"

Developer integrations. 1Password CLI has first-class integrations with several developer tools:

  • op run injects secrets from .env template files with op://vault/item/field syntax. No plaintext secrets are written to disk.
  • Git commit signing via the SSH agent integration: op signs commits with an SSH key stored in the vault.
  • Terraform provider: 1password/onepassword provider for Vault (not HashiCorp Vault — 1Password's own) reads and writes secrets from Terraform plans.
  • Kubernetes secret injection: op inject renders Kubernetes Secret manifests with vault references resolved at deployment time.

Dev mode and shell plugins. op plugin init aws configures the AWS CLI to pull credentials from the vault on every invocation. The same mechanism exists for GitHub CLI, Stripe CLI, Fastly CLI, and others. For developers using multiple CLIs with rotating credentials, this eliminates the credential-file pattern entirely.

Encryption specification. 1Password uses AES-256-GCM for vault data, with keys protected by the Secret Key + Master Password dual-key model. The secret key (128 bits of random entropy generated at account creation) is stored only on the user's devices, never on 1Password's servers. Key derivation uses PBKDF2-SHA256 (650,000 iterations for the master password component). The combined model means a server breach alone cannot decrypt any vault data.

Pricing. Individual: $36/year ($2.99/month) — unlimited passwords, 1 GB document storage, Travel Mode, 1Password.com browser integration. Teams Starter: $19.95/month for up to 10 users — guest accounts, shared vaults, granular permissions. Business: $8/user/month — advanced RBAC, custom roles, Splunk/SIEM integration, audit events API. Enterprise: custom pricing — SSO/SCIM provisioning, custom security reviews, dedicated support. No free tier. No self-hosted option.

pass deep-dive

pass is the Standard Unix Password Manager. Created by Jason Donenfeld (also the author of WireGuard), it is a Bash script — the entire program, including sync, generation, and editing, is fewer than 600 lines of shell. The design philosophy is explicit: one text file per secret, encrypted with GPG, stored in a directory tree, synchronized over git.

Core mechanics. The password store lives at ~/.password-store by default. Each entry is a .gpg file whose plaintext is typically a password on the first line followed by metadata (URL, username, notes) on subsequent lines. The convention is respected by every pass-compatible client.

~/.password-store/
  production/
    postgres.gpg        # password line 1, notes below
    api-key-stripe.gpg
  personal/
    email.gpg

Encrypting a new secret:

pass insert production/redis-password
# or with multiline:
pass insert --multiline production/postgres

Reading:

pass production/postgres            # outputs to stdout
pass -c production/postgres         # copies to clipboard, clears in 45s

GPG model. Each .gpg file is encrypted to one or more GPG public key IDs specified in .gpg-id files at the directory level. This is how multi-recipient access works: add team members' key fingerprints to .gpg-id, then re-encrypt with pass init --reencrypt. Every secret in the subtree gets re-encrypted to all listed keys.

The security model is as transparent as it gets: you are trusting GnuPG, your own key management, and the git hosting provider. There is no middleware, no proprietary binary, no cloud authentication flow. The threat model is correspondingly simple to reason about.

Git sync. pass git proxies git commands directly. pass git push, pass git pull. The git history stores every change with a commit message that intentionally reveals only the operation type (add, edit, delete) and the entry path — the content remains encrypted. For teams, a shared bare repository on a private git host (GitHub, GitLab, self-hosted Gitea) is the standard setup.

Ecosystem. pass has a wide ecosystem:

  • passff / browserpass: browser extensions for Firefox and Chrome that inject credentials from the store.
  • Android Password Store (now called OpenKeychain + APS): Android client with full pass compatibility.
  • QtPass: cross-platform GUI.
  • pass-otp: plugin for TOTP codes — pass otp production/totp-key.

Limitations. The Unix philosophy cuts both ways. There is no native team management UI, no access logs, no breach detection, no mobile app maintained by the same team, no help desk. GPG key management at scale is genuinely painful: when a team member leaves, you remove their key from .gpg-id and re-encrypt every secret they had access to. For a team of 20, this can take several minutes and requires all remaining team members' public keys to be current in everyone's keyring. gopass addresses most of these pain points.

Price. Free. MIT licensed. No accounts, no subscriptions.

gopass deep-dive

gopass is pass, rewritten in Go, with structured secrets, team commands, and a pluggable backend. It was created by engineers at Codecentric and is actively maintained as of 2026. The primary binary, gopass, is a drop-in replacement for pass — it reads and writes the same store format — while adding capabilities that pass lacks at scale.

Structured secrets. Where pass stores a blob of text per entry, gopass supports a YAML-like key-value format inside the encrypted file:

gopass insert --multiline production/postgres
# plaintext inside the .gpg:
---
password: hunter2
username: postgres
host: db.prod.example.com
port: 5432

Fields are then accessible individually:

gopass show production/postgres password   # just the password field
gopass show production/postgres host       # just the host

This is significant for CI/CD: individual fields can be injected into environment variables without parsing multi-line output.

Mounts. gopass supports multiple password stores ("mounts") accessible under namespace prefixes:

gopass mounts add work   git@github.com:mycompany/passwords.git
gopass mounts add home   ~/.personal-pass

Secrets live at work/production/postgres or home/personal/email. Each mount is a separate git repository with its own .gpg-id. This is the correct model for a developer who has a work vault and a personal vault that must never be mixed.

Team workflows. gopass has first-class team management commands:

  • gopass recipients add --store work "colleague@example.com" — adds a recipient's GPG key from your keyring, then re-encrypts only the affected mount.
  • gopass recipients rm --store work "departed@example.com" — removes a key and re-encrypts.
  • gopass audit — checks for weak passwords and duplicate entries across all mounts.

The re-encryption on team membership change is still O(number of secrets), but gopass parallelizes it and only re-encrypts the affected mount, not the entire store.

age encryption support. Since version 1.14, gopass supports age (a modern encryption tool by Filippo Valsorda) as an alternative to GPG. age has a simpler key format (X25519 keys, SSH keys, or passphrase-derived keys), no key server dependency, and a more auditable codebase. For new stores, age is recommended over GPG if the team has no existing GPG infrastructure.

gopass init --crypto age

Template rendering. gopass has a gopass env subcommand that resolves secret references in an environment template:

DATABASE_URL=postgres://{{ gopass "production/postgres/username" }}:{{ gopass "production/postgres/password" }}@{{ gopass "production/postgres/host" }}:5432/mydb

Not as polished as op run, but functional for most pipeline use cases.

Companion apps. gopass has browser integration via the gopass bridge for Chrome and Firefox. The Android app is maintained separately. There is no official iOS client, though the pass ecosystem clients (which read the same store format) fill that gap partially.

Price. Free. MIT licensed.

Comparison matrix: 4 tools × 12 criteria

CriterionBitwarden CLI1Password CLIpassgopass
EncryptionAES-256-CBC + Argon2idAES-256-GCM + PBKDF2 (650k)GnuPG (RSA/Ed25519)GnuPG or age (X25519)
Sync modelCloud (Bitwarden.com or self-hosted)Cloud only (1Password.com)git (any remote)git per mount (any remote)
Dev integrationbw run, env vars, REST APIop run, shell plugins, TerraformManual / scriptedgopass env, template rendering
CI/CD supportAPI key auth, BW_SESSION patternService accounts, OP_SERVICE_ACCOUNT_TOKENGPG agent + gitGPG/age agent + git
SSH agentNone native (workaround via scripts)Native socket (agent.sock), biometric unlockManual (ssh-add from piped decrypt)gopass ssh helper, manual
Team sharingOrg vaults, group RBACShared vaults, granular ACL.gpg-id per dir, manual re-encryptgopass recipients, mount-level ACL
PriceFree / $4/user/mo (Teams)$36/yr individual / $8/user/mo (Biz)FreeFree
Mobile companionOfficial iOS + AndroidOfficial iOS + AndroidCommunity (APS, OpenKeychain)Community (pass-compatible apps)
Biometric unlockVia device app (iOS/Android)Native (Touch ID, Windows Hello, Face ID)NoneNone
Audit logEvents log (Teams+)Audit events API (Business+)git log onlygit log + gopass audit
ScriptabilityHigh (bw get, JSON output)Highest (op read, structured fields, plugins)High (Unix pipes, Bash-native)Very high (structured fields, gopass show field)
Learning curveLow (guided onboarding, GUI parity)Low-medium (concepts: vaults, items, fields)High (GPG setup, key management)Medium-high (GPG or age + mounts concept)

Encryption notes. AES-256-GCM (1Password) provides authenticated encryption natively, while AES-256-CBC (Bitwarden) requires a separate MAC. In practice, both implementations are sound. The GnuPG path for pass and gopass has a larger attack surface in terms of library complexity, but the code has been audited extensively and the trust model is more transparent. age is the cleanest option from a cryptographic design standpoint: X25519 key exchange, ChaCha20-Poly1305 payload encryption, no algorithm agility footgun.

Sync model notes. Cloud-synced tools (Bitwarden, 1Password) are simpler to operate: install, authenticate, done. git-based tools require you to host a git repository, manage clone/push/pull discipline, and handle merge conflicts if two team members edit simultaneously. The upside is that git-based tools have no mandatory cloud dependency — the vault can live entirely on infrastructure you control.

CI/CD support notes. 1Password's service account model is the most mature: a single token, scoped to specific vaults, revocable without affecting any human user's session. Bitwarden's API key model works well but requires keeping the session token fresh (the bw unlock step adds 300–600 ms latency). pass and gopass are viable in CI when the GPG private key is available as a pipeline secret — a pattern that has its own key custody issues.

Recommendations by profile

Indie developer (solo, no team). Use Bitwarden CLI on a free account for anything that does not require SSH agent integration, and 1Password if you want SSH key management out of the box. For the strongly privacy-minded solo developer who wants zero cloud dependency: gopass with age encryption on a private git repository you host. The learning curve is real but the trust model is the cleanest available.

Team of 5–20 developers. Start with 1Password Teams if budget allows — the SSH agent integration, op run for CI/CD, service accounts for pipelines, and the audit log cover 95% of what a team this size needs, with minimal operational overhead. If budget is a constraint or self-hosting is a hard requirement, Bitwarden Teams ($4/user/month, self-hostable via Vaultwarden) is the correct choice. Avoid pass or gopass at this scale unless the team has dedicated GPG key management expertise; the operational cost of membership churn is high.

Enterprise (100+ developers). 1Password Business or Bitwarden Enterprise (self-hosted). The differentiating factors are SSO/SCIM provisioning (1Password has OIDC and SAML; Bitwarden has SCIM directory connector), audit log export to SIEM (both support it at the top tier), and compliance reporting. 1Password's enterprise tier includes advanced protection policies and on-demand security reviews. Bitwarden's self-hosted path is preferred by organizations that cannot tolerate a cloud dependency for key material, even under a shared-responsibility model.

Paranoid power user / secrets rotation specialist. gopass with age on a private git repository, GPG master key on an air-gapped device or a Yubikey, day-to-day operations signed with a subkey. For secrets rotation, build a rotation script that calls gopass show <secret>, hits the service API to rotate, and calls gopass insert <secret> with the new value. The entire pipeline runs locally with no cloud call except to the target service. For SSH, combine gopass with ssh-add in a startup script — less ergonomic than 1Password's agent but fully auditable. Add gopass audit to your weekly cron to catch weak or duplicate secrets before they become a compliance issue.

For a foundational read on the broader threat model that makes secrets management critical, see our state of browser privacy 2026 pillar. For a reference on hardening the OS layer that underlies any secrets workflow, our Lockdown Mode analysis covers how the OS-level attack surface interacts with credential stores at the application layer.

Whichever tool you choose, the non-negotiable baseline is this: no plaintext credential touches a repository, a log file, or an environment variable dashboard. A CLI password manager is the mechanism that makes that baseline maintainable at engineering velocity.

Photo: Lukas — Unsplash (source)

Also available in