On this page
Secret zero is the first credential a machine, container or pipeline needs in order to authenticate to a secrets vault, the one secret that can't come from the vault itself because the workload must already hold it before it can ask the vault for anything.
The bootstrap problem
Moving every secret into a vault leaves one behind: the credential that lets an application into the vault. If that credential sits in a config file or a CI variable, an attacker who finds it gets everything the application could fetch. The vault has moved the problem, not removed it.
HashiCorp calls this the "secure introduction" challenge: "Getting the first secret to the consumer", and asks, "How does a secret consumer, an application or machine, prove that it is the legitimate recipient for a secret so that it can acquire a token?" (HashiCorp).
Ways to shrink it
There is no way to have zero secrets; there are ways to make the first one worth very little.
- Use an identity the platform already provides. A CI job's OIDC token, a cloud instance's role, a Kubernetes service account token. The platform vouches for the workload, so nothing has to be stored. See workload identity federation.
- Make it single-use and short-lived. A bootstrap code that works once, for minutes, is useless after the machine has used it, and an attempt to reuse it is a signal.
- Keep it out of arguments and history. Pass it through standard input or an environment variable, not as a command-line argument that shows up in process lists and shell history.
- Verify the other side. The person setting up the machine should confirm they are talking to the right workload, for example by comparing a fingerprint.
Common mistakes
- A long-lived vault token in CI settings. It is the most valuable secret in the pipeline and the least protected.
- The same bootstrap token for every machine. One leak enrolls anything.
- Baking it into an image. Everyone who can pull the image has it.
How Crunu handles it
Machines. An admin creates the machine in the web app and gets a one-time enrollment code, valid for 15 minutes by default and at most 24 hours, optionally limited to addresses. On the server, crunu enroll reads the code only from standard input or the CRUNU_ENROLL_CODE variable, never from an argument, and prints the machine's fingerprint; the admin approves the machine after comparing it. The code is used up on first use, and presenting it again marks the machine as a possible interception and raises an alert. After enrollment the machine has its own keys, and the code is worth nothing.
printf '%s\n' "$CODE" | sudo crunu enroll --server https://app.crunu.com -CI. A pipeline's service token is a stored secret, and in a plain setup it is secret zero. A CI binding (OIDC) changes what it is worth: with a binding, the token signs in only together with a fresh JWT that the CI provider issues to a matching job, and each JWT works once. A token copied out of CI settings then fails anywhere else. The token also gets only its own environments, and can have a lease and a usage limit. See CI/CD secrets with OIDC.
Sources
- HashiCorp: Secure introduction of Vault clients, checked October 30, 2026.
From the blog
CI/CD
GitLab CI OIDC without Premium: id_tokens on the Free tier
The secrets keyword needs GitLab Premium, but id_tokens works on Free. How to exchange a job's ID token for AWS, Google Cloud, Azure or Crunu by hand.
CI and OIDC guide
CI/CD
Bitbucket Pipelines OIDC: the step token explained
What oidc: true gives a Bitbucket step: the BITBUCKET_STEP_OIDC_TOKEN, the workspace issuer, audiences, the sub claim and how to pin a trust policy to it.
CI and OIDC guide
Security
Why a blind-server vault can't issue dynamic secrets
Dynamic secrets need a server that holds a privileged credential and uses it alone. A server that can't decrypt values can't, so Crunu doesn't offer them.
Who can decrypt guide