A password, an API key or a token in your code is a loose key to your systems. Public repositories are scanned continuously by automated tools looking for them, and a leaked cloud key can be used within minutes. The fix is a set of habits, and an emergency plan for when they fail.
What counts as a secret
Anything that grants access or proves identity: API keys, database passwords and connection strings, private keys and certificates, signing secrets, OAuth client secrets and tokens, webhook secrets. A good test: if a stranger had this, what could they do?
How to keep them out of code
Read them from the environment instead of writing them in the file:
import os
API_KEY = os.environ["PAYMENTS_API_KEY"] # fails loudly if it is missing
os.environ[...] raises an error when the variable is not set, which is better than quietly running with a default.
For local development use a .env file that is ignored by Git, and commit a template next to it:
# .env.example (committed: placeholder values only)
PAYMENTS_API_KEY=replace-me
DATABASE_URL=postgresql://user:password@localhost:5432/app
# .gitignore
.env
*.pem
*.key
Do this before the first commit, because a file that was ever committed stays in history.
Production
Keep production secrets in a secret manager rather than in files or in the repository, give each service access only to the secrets it needs, and log who reads them. Keep separate secrets per environment so that a leak in a test system does not open production.
The checklist, and why
The list above works as a review. In short: keep secrets out of the repository and out of images; give each one the smallest power it needs and its own environment; look for the ones already there, including in old commits; rotate them; and keep them out of logs and URLs.
If one leaks
Speed matters more than tidiness.
- Revoke or rotate the secret immediately. Do this before anything else. A key that no longer works is no longer a risk.
- Replace it everywhere it is used, and check the new one works.
- Check for misuse: look at the provider's access logs and billing for activity you do not recognise, and at what that key could reach.
- Then clean up: remove it from the current code, and consider rewriting history to drop it (tools exist for this), knowing that copies may remain.
- Learn from it: add the scanning or the ignore rule that would have caught it, and tell the team what happened without blame.
Common slips
- Notebooks and screenshots. Output cells and screenshots of terminals or consoles contain keys.
- Build and CI logs. A command that prints its environment writes your secrets into a log many people can read.
- Front-end code. Anything shipped to a browser is public. A secret key must stay on a server, and the browser should talk to your server instead.
- Shared documents and chat. Paste a secret into a chat and it lives in the archive.
- Default and example passwords left in a deployed system.
Checklist
- Never write a secret into source code, a config file in the repository, a Dockerfile, a notebook or a build log. Read it from the environment or a secret manager at run time.
- Add .env files and key files to .gitignore before the first commit, and commit a .env.example with placeholder values instead.
- Use a secret manager (your cloud provider's, or a dedicated tool) for production, with access limited to the services that need each secret.
- Give every environment its own secrets. A leak from development must not unlock production.
- Give each key the least privilege it needs: read-only where reading is enough, limited to one project, one bucket, one API.
- Scan for secrets: a pre-commit hook on developer machines, the hosting platform's secret scanning, and a scan of the full history, not only the latest commit.
- Rotate secrets on a schedule and whenever someone with access leaves, and make rotation easy enough that you will actually do it.
- Keep secrets out of logs, error messages, URLs and analytics events. A key in a query string ends up in logs and browser history.
- Treat any secret that has ever been committed, pasted in chat or shown on screen as compromised, even if the repository is private and the commit was deleted.
- Write down the leak procedure now: who to tell, how to revoke each type of key, and where to check for misuse.
Frequently asked questions
I deleted the commit. Is the key safe now?
No. Copies may exist in clones, forks, caches and build logs, and automated scanners find keys within minutes of a public push. Revoke and replace the key first; cleaning history is secondary.
Are environment variables secure enough?
They keep secrets out of code, which is the main goal, but they can show up in process listings, crash reports and debug pages. Production systems usually fetch them from a secret manager and limit who can read them.
References
From Grokem: https://www.grokem.com/cybersecurity/application-security/secrets-in-code-checklist



