Secrets and identities
Summary: secrets — API keys, database passwords, tokens, certificates — are the most profitable target for an attacker, and the most mundane source of incidents. This lesson explains why a secret in Git is definitively compromised, how a secrets vault works, and why the most modern approach is to eliminate long-lived secrets altogether.
1. The problem of the secret in the repository
The point to remember absolutely: a secret that has passed through Git is definitively compromised, even if you removed it, even if the repository is private, even if you rewrote the history. Local clones, platform caches and backups may keep a copy of it.
The only valid response is revocation. Generate a new key, revoke the old one, and consider the old one public.
A clarification about private repositories: they reduce the risk but do not eliminate it. A private repository can become public by mistake, an account with access can be compromised, and a former collaborator keeps their local clone.
2. Where NOT to put your secrets
Case 3 often surprises people and deserves an explanation. A container image is made of stacked layers. If one instruction copies a secret and a following instruction deletes it, the intermediate layer still contains the secret. Inspecting the image history is enough to retrieve it.
Case 5 is particularly insidious because it is unintentional. A logging statement that prints a complete request object can write authentication tokens into logs kept for several weeks and viewable by the whole team. Systematically configure a list of fields to mask in your logging library.
3. The secrets vault
Function 5 is the most elegant conceptually. Instead of sharing a permanent database password across ten services, the vault generates one on demand, valid for one hour, specific to this service and this session. A stolen secret becomes unusable almost immediately, and the log makes it possible to know exactly which service did what.
To get started without complexity: your CI tool's encrypted secrets (GitHub Actions secrets, GitLab protected variables) are already a considerable improvement over a versioned file. Don't wait until you can deploy Vault.
4. The ephemeral identity revolution
This is the most important development of recent years on this topic.
The phrase that sums up the idea: "the best secret is the one that doesn't exist". A secret you don't have cannot leak, requires no rotation, and won't linger in some forgotten old configuration file.
Concrete recommendation in 2026: if you are setting up a deployment today from GitHub Actions or GitLab CI to AWS, Azure or Google Cloud, use OIDC rather than permanent access keys. The configuration takes one extra hour the first time, and removes an entire category of risks.
5. Least privilege applied
The method that actually works: start with zero permissions, launch your application, watch what fails, add exactly the missing permission, repeat. It is tedious the first time, but it is the only approach that produces a correct set of rights — and it documents in passing what your application really does.
6. The special case of user passwords
The most important practical rule here: never implement password handling yourself. Use your framework's authentication module, which already applies bcrypt or Argon2 with a proper salt. Every home-made password hashing implementation is an opportunity for error, and the error is invisible until the breach.
7. Detecting secrets in code
Level 1 is by far the most effective, because it prevents the problem instead of flagging it. Once the secret is in the history, however fast the detection, revocation becomes mandatory. A local hook avoids this situation entirely.
Level 4 is worth doing at least once. Analyze the full history of your existing repositories — most teams that do it for the first time discover old forgotten secrets, still valid.
Remember in 30 seconds
- A secret that has passed through Git is definitively compromised. The only correct response is revocation, not cleanup.
- On a public repository, the delay between a key being published and exploited is often counted in minutes.
- Never a secret in the code, a versioned file, a container image, frontend code, the logs or chat.
- A container image keeps secrets in its layers, even if a later instruction deletes them.
- A secrets vault brings: encryption, fine-grained access, audit log, rotation, and dynamic secrets with a short lifespan.
- To get started: your CI tool's encrypted secrets are enough. Don't wait to deploy Vault.
- The modern approach: eliminate long-lived secrets in favor of ephemeral identities via OIDC. "The best secret is the one that doesn't exist."
- Least privilege: start from zero rights and add what's missing. It doesn't prevent compromise, it limits its impact.
- User passwords: bcrypt, scrypt or Argon2, with a unique salt. Slowness is a feature.
- Never implement password hashing yourself — use your framework.
- A local pre-commit hook is the most effective protection against secret leaks.