Security › Authentication & Authorization
Secrets in Git
Why passwords and keys must never be committed, and what to do when one is.
Also known as: committed secrets, leaked credentials in git, API key in repo, hardcoded secrets
A secret is anything that grants access: passwords, API keys, tokens, private keys, database URLs with credentials. Never commit them to Git. Not in a private repo, not “just for now”, not in a file you plan to delete.
Why this goes wrong so badly
- Git remembers everything. Deleting the file in a later commit doesn’t remove it from history. Anyone with the repo (or a clone from last month) can read it.
- Repos get shared. Private repos become public, are cloned to laptops, forked, pasted into tickets and given to contractors.
- Attackers scan. Automated bots watch public code hosting for new commits containing keys, and exploitation can start within minutes of a push. Treat a public leak as an immediate compromise.
# never
STRIPE_KEY = "sk_live_51H..."
db_url = "postgres://admin:hunter2@prod-db/app"
What to do instead
- Read secrets from the environment or a secrets manager at runtime (environment variables, secrets management).
- Add
.envand key files to.gitignorefrom the start (.gitignore). Commit a.env.examplewith fake values. - Use separate secrets per environment, so a leaked development key can’t touch production.
- In CI, use the platform’s encrypted secrets (CI secrets).
- Add a secret scanner as a pre-commit hook and in CI (tools like gitleaks and the secret scanning built into code hosts catch common key formats).
If one gets committed
- Revoke or rotate the secret immediately. This is the step that actually fixes it (secret rotation). Assume it’s compromised, even if you removed it a minute later.
- Check for misuse: look at the provider’s access logs and billing.
- Then clean up: remove it from history if you want to (rewriting history is disruptive, see removing secrets from history), and tell your team.
- Find out how it happened and add a guard so it can’t again.
Deleting a leaked secret from Git without rotating it only hides the evidence. The key still works.