Password store vs secret vault: picking your threat model
Every secrets-migration guide ends the same way: “put your secrets in a
password manager and never touch .env again.” Then you open the tool
comparison and find two families of products treated as interchangeable:
password stores like pass, and secret vaults like Bitwarden or HashiCorp
Vault. They are not the same thing. They defend against different attackers,
and picking one by feature list instead of threat model is how you end up
with a store that feels secure and is not.
What a password store actually is
A password store is a directory of encrypted files. pass is the canonical
example: one GPG-encrypted file per secret, arranged in a tree, with your GPG
key as the single unlock mechanism. There is no server, no database, no user
model. If you have the private key — or an unlocked gpg-agent — you can read
every entry.
That simplicity is the threat model. A password store assumes one user, one machine, one key. It defends against a stolen laptop, because the files are encrypted at rest, and against casual prying. It does not defend against a second user, because there is no notion of a second user.
What a secret vault actually is
A vault is a centralized encrypted database with an access layer on top. Bitwarden (or a self-hosted Vaultwarden) is a password manager with sync, collections, and sharing. HashiCorp Vault is a different animal: a server that issues credentials on demand, with dynamic secrets, leases, policies, and revocation built into the API.
The common thread is mediation. Reads go through the vault, which can enforce policies, log access, and revoke. That is a richer control surface than a file tree — and it costs you a server, a session model, and a sync story.
The threat model question
Before choosing a tool, decide what you are defending against:
- A stolen or lost machine. Both win, as long as disk encryption is on and the master password is strong. The vault adds nothing here.
- A hostile process on the same machine. Both lose the same way. An
unlocked store — an agent holding your GPG key, a
bwsession in an environment variable — is readable by anything running as you. The defense is not the store; it is not handing the decrypted value to more processes than necessary. - A compromised agent or tool. Neither a store nor a vault saves you, because the agent asks for the secret in plaintext and receives it in plaintext. This is where the broker pattern enters: the agent references a secret by name, a broker injects it at process spawn or transport time, and output is sanitized before it reaches the agent’s context.
- Team access and revocation. The vault wins outright. Revoking a person
in
passmeans re-encrypting files or rotating the secret itself; a vault revokes a session.
Where the store choice stops mattering
For agent setups, the store is an implementation detail once a broker sits in
front of it. What matters is that the broker can read the store
non-interactively and fail closed. pass decrypts with the GPG key.
Bitwarden uses a session key held in an environment variable — never argv,
where process listings could see it — and refuses to proceed when the session
is invalid.
trustless reads both: pass by
default, Bitwarden through the bw CLI with fail-closed session handling.
Both backends power the same injection, sanitization, and DLP layers, which
is the point: your threat model should decide the store, and the store should
not decide your security posture. The backend design is documented on the
architecture page.
Pick the store that matches your real attacker, and spend the rest of your budget on the layer between the agent and the plaintext. What are you actually defending against: a stolen laptop, a hostile process, or a compromised agent?