GUIDE · COMPARISON 11 min ·

The secret-zero problem explainedYou moved the secret. You didn't fix it.

You moved all your credentials into a vault. The vault needed a token. That token is sitting in your shell environment right now. You shifted the problem one level up, not away.

TL;DR· the answer, in twenty seconds

What: Secret zero is the bootstrap credential your secrets manager requires to unlock itself. Every tool that stores secrets needs one, and that credential lives somewhere: usually your shell environment or a config file, in plain text.

Fix: The genuine answers are OS keychain integration with biometric unlock, ambient cloud identity (IAM roles bound to the instance, not to a static key), or hardware tokens. Rotating the bootstrap token is not a fix; it is a recurring cost you pay because you haven't fixed it.

Lesson: Secrets management is a solved problem in production cloud workloads. On a developer laptop with an AI coding agent in the session, it mostly isn't.

You read a post-mortem, or a GitGuardian report, or you found a leaked API key in a git log. You set up a secrets manager. Doppler, Infisical, HashiCorp Vault, 1Password CLI. You pulled every credential out of .env and into the vault. You felt better.

Then you looked at your shell startup file and saw DOPPLER_TOKEN=dp.st.prod.xxxxxxxxxxxx sitting there, or VAULT_TOKEN=hvs.xxxxxxxxxx. Or you found a .vault-token file in your home directory. The keys were gone. The lock was still exposed.

That is the secret-zero problem. Every secrets manager needs a credential to open itself, and something has to hold that credential. You moved twenty secrets into a vault. The vault gave you one secret back. The number went from twenty to one, which is progress. But the fundamental problem, a plaintext credential that grants access to everything, is still there.

This is not a bug in any of these tools. It is the logical floor of software-based authentication. At some point, you have to trust something that proves identity without asking for another credential first.

What secret zero means in practice

Short version, five points:

  1. Every secrets manager requires a bootstrap credential: a token, a password, a key file, a client secret.
  2. That credential lives somewhere: environment variable, config file, OS keychain, hardware token, ambient cloud identity.
  3. Where it lives determines how exposed it is, how long-lived it is, and whether an agent that inherits your session can read it.
  4. Rotating the credential does not change where it lives. It changes the value. The exposure surface stays the same.
  5. There are four genuine answers to secret zero. The rest are mitigations.

How each tool handles the bootstrap credential

None of these tools fully eliminate secret zero. Some handle it better than others in specific contexts.

Doppler, Infisical, SOPS

All three work the same way at the bootstrap layer. You authenticate once and receive a service token. That token goes into an environment variable or a config file. Doppler's CLI reads DOPPLER_TOKEN. Infisical's reads INFISICAL_TOKEN. SOPS decrypts with a KMS key reference that still needs AWS or GCP credentials behind it.

The marketing says "replace all your secrets with one token." That is accurate. It is also the problem restated as a feature. One long-lived token with broad read access to your secret namespace is, in practice, more dangerous than the individual credentials it replaced, because it is the master key. If it leaks, everything leaks.

SOPS is at least honest about the trade: it requires you to already have working cloud credentials or a PGP key, and it does not pretend the bootstrap credential away.

HashiCorp Vault

Vault has done the most serious thinking about secret zero of any tool in this category. It ships multiple auth methods specifically designed to eliminate a static bootstrap token:

  • AppRole: a role-id and secret-id pair, where the secret-id is short-lived and consumed on first use. Better than a static token, but you still need to deliver the secret-id somehow.
  • AWS IAM auth: the instance proves its identity by signing a request with the instance's IAM role. No static secret. The IAM identity is the bootstrap credential, scoped to the instance by the cloud provider.
  • Kubernetes service accounts: the pod presents its service account JWT, Vault validates it against the Kubernetes API. The service account binding is the bootstrap, managed by the cluster.
  • TLS certificates: mutual TLS where the certificate is the auth credential. Needs a PKI, but certificates are revocable and short-lived.

For production workloads on AWS, GCP, or in Kubernetes, Vault's auth backends are a genuine answer to secret zero. The cloud provider or the cluster operator holds the identity, and that identity is scoped by policy.

On a developer laptop, none of this applies. You fall back to VAULT_TOKEN in the environment or ~/.vault-token on disk. Vault on a laptop is no better than Doppler for secret zero purposes.

1Password CLI

The 1Password CLI approach is different. It uses the OS keychain plus biometric authentication (Touch ID or Windows Hello) to unlock the vault. The bootstrap credential is your fingerprint or face, verified by hardware on the device. The service account token for automated pipelines is a separate concern.

For an individual developer on macOS, this is the best answer available without cloud infrastructure. The biometric check happens at the OS level. The vault key does not appear as an environment variable a child process can read. 1Password CLI's op run injects secrets into a subprocess's environment without exposing them to the parent shell.

The limitation: biometric auth does not scale to CI/CD or multi-user systems, and the 1Password service account token used in those contexts is back to being a static credential you have to store somewhere.

Cloud-native secret stores (AWS Parameter Store, GCP Secret Manager, Azure Key Vault)

AWS Parameter Store and GCP Secret Manager sidestep the credential problem by making the IAM identity the bootstrap. An EC2 instance or Lambda function authenticates to Parameter Store using its instance profile. No static secret. The IAM role is the credential, and the cloud provider manages the proof of identity.

This works well. On a compute instance, the metadata endpoint hands out temporary credentials that rotate automatically. You never see them as environment variables. The IAM role's scope is the secret zero, not a token you issued yourself.

On a developer laptop, you need an IAM user with a static access key to call the AWS SDK. That key is in ~/.aws/credentials or AWS_ACCESS_KEY_ID in your environment. The problem moved from "secrets in env" to "one IAM key in env," which is an improvement in blast radius but not a structural solution.

The honest version: cloud-native secret stores solve secret zero for cloud workloads. They do not solve it for local developer environments.

Secret zero and AI coding agents

AI coding agents make secret zero more urgent because they inherit the session that started them.

When you run Claude Code, Codex CLI, Cursor, or Aider from a terminal, the agent subprocess gets your full environment. Every variable exported in your shell goes with it. That includes VAULT_TOKEN, DOPPLER_TOKEN, AWS_ACCESS_KEY_ID, and anything else you loaded to authenticate your tooling.

GitGuardian's 2026 State of Secrets Sprawl found that AI-assisted commits leak around twice as often as the baseline. Part of that is agents writing to state files that end up in published packages (Knostic found this in Claude Code's settings.local.json in February 2026). Part of it is agents operating in sessions where the secret-zero credential is just another environment variable.

The agent does not need to be malicious for this to be a problem. It needs only to write a debug file, a cache entry, or a log line that captures its environment. Then it needs to be running in a session where the vault bootstrap token is set. The rest follows.

If you give an agent an op run-style injection where the token appears only in the child process, you have a better posture. If the token is in your shell and the agent inherits the shell, you have not improved anything.

Rotation is not a fix for secret zero

The standard advice after a credential leak is to rotate the credential. Rotation is a correct response to a known compromise. It is not a structural fix for secret zero.

A rotated token is still a static token. It lives in the same environment variable. It grants the same access. A scraper that reads your ~/.zshrc or your CI logs or your agent's state file gets the new value just as easily as the old one.

Rotation is a tax you pay because you haven't fixed the bootstrap problem. It is useful because it limits the window of exposure after a breach. It does not shrink the exposure surface.

Short rotation periods (hours instead of months) meaningfully reduce blast radius. Automatic rotation via Vault's token renewal or AWS STS is better than manual rotation. Neither changes the fact that a static credential exists in an environment variable that any child process can read.

The framing "we rotate tokens every 24 hours" often appears in documentation as though it resolves the question. It does not. It just means the attacker has 24 hours instead of forever.

What actually solves secret zero

Four approaches work structurally. Everything else is risk reduction within the same flawed model.

OS keychain with biometric unlock. The vault key sits in the OS keychain, protected by the secure enclave. A fingerprint or face scan unlocks it. No environment variable. No file on disk readable by a child process. The biometric is the secret zero, and it stays on hardware. This is what 1Password CLI does on macOS and what macOS Keychain does natively. Works for individual developers. Does not generalize to CI or server contexts.

Ambient cloud identity. The cloud provider issues temporary, scoped credentials to the compute resource, verified by hardware attestation inside the data center. AWS instance profiles, GCP workload identity, Azure managed identity. No static secret you issued. The IAM binding is the bootstrap, managed outside your codebase. Works for production and CI/CD on cloud infrastructure. Does not work on a developer laptop without a proxy or a local simulation layer.

Hardware tokens. A YubiKey or similar device holds the private key material in tamper-resistant hardware. The credential never leaves the device. Authentication requires physical presence. Works for individual access in high-security contexts. Poor ergonomics for developer workflows that require frequent automated access.

Process-scoped injection. The tool that knows the secret injects it into a single child process at exec time and withholds it from the parent shell and from any sibling process. The credential exists in memory for the duration of one command and then is gone. This is what op run approximates for 1Password and what a proper secret broker does for agent workflows. It does not eliminate secret zero, but it eliminates the environmental persistence that makes secret zero dangerous.

The process-scoped model is the most achievable answer for local developer environments without cloud infrastructure or hardware tokens.

A checklist for auditing your secret-zero exposure

## Secret-zero audit

- [ ] Identified the bootstrap credential for each secrets tool in use
- [ ] Confirmed that credential is not in ~/.zshrc, ~/.bashrc, or ~/.bash_profile
- [ ] Confirmed that credential is not in any dotenv file in a project repo
- [ ] Checked ~/.vault-token, ~/.doppler-token, ~/.config/op/ for long-lived tokens
- [ ] Verified that CI/CD uses short-lived credentials (OIDC, IAM role, not static keys)
- [ ] Audited which secrets are available to AI agent sessions (grep shell env before launch)
- [ ] For macOS: vault access via OS keychain or biometric, not plaintext env var
- [ ] For cloud workloads: IAM role or workload identity, not hardcoded access key
- [ ] For agent workflows: injection scoped to child process, not exported to shell
- [ ] Confirmed rotation schedule exists AND that rotation is automatic, not manual
- [ ] Checked state files written by coding agents for captured environment data

What this means for your stack

The answers available to you depend on where your workload runs. For production cloud infrastructure, ambient identity (IAM roles, GCP workload identity, Kubernetes service accounts) solves secret zero structurally. For CI/CD, OIDC tokens from GitHub Actions or GitLab CI give you short-lived credentials without static secrets. For individual developers on macOS, the OS keychain with biometric unlock is the closest thing to a real answer.

The remaining hard case is local developer sessions with AI coding agents. The agent inherits your shell. Your shell holds the vault bootstrap token. You can strip the environment before launching the agent (env -i with explicit allowlists), but that breaks most tooling. You can use op run-style subprocess injection, which helps if every secret access goes through it. Or you can use a local broker that holds credentials in an encrypted vault, injects them into specific child processes at exec time, and keeps an audit log of every grant.

hasp does the last one. Encrypted local vault (Argon2id passphrase, AEAD at rest), per-session grants with a 24-hour ceiling, and injection scoped to the agent's process tree. curl -fsSL https://gethasp.com/install.sh | sh, hasp setup, bind a project, and the next agent session gets a reference instead of the raw credential. Source-available (FCL-1.0), macOS and Linux, no account, no telemetry.

The bootstrap problem does not disappear with any of these. The Argon2id passphrase is a secret zero too. But it lives in your memory and unlocks via the OS keychain on subsequent sessions, which is a different risk model than a token sitting in ~/.zshrc that your agent reads every time you open a terminal.

Fix the exposure surface first. Rotation schedules are for when you can't.

Sources· cited above, in one place

NEXT STEP~90 seconds

Stop handing the agent your real keys.

hasp keeps secrets in one local encrypted vault, brokers them into the child process at exec, and never lets the agent read the value.

  • Local, encrypted vault — no account, no cloud, no telemetry by default.
  • Brokered run — agent gets a reference, the child process gets the value.
  • Pre-commit + pre-push hooks catch managed values before they ship.
  • Append-only HMAC audit log answers "did the agent touch the prod token?" in seconds.
→ okvault unlocked · binding ./api
→ okgrant once · pid 88421
→ okagent never read

macOS & Linux. Source-available (FCL-1.0, converts to Apache 2.0). No account.

Browse all clusters· eight threads, one index