DEV Community

DatanestDigital
DatanestDigital

Posted on

Stop Hardcoding Secrets: A Practical Secrets-Management Guide (2026)

Every secret leak starts the same way: someone, under deadline pressure, pastes an API key directly into the code "just to test it," and forgets. Six months later it's in your git history, on a laptop backup, and in a screenshot in a Slack thread. By the time you notice, it has been public for weeks.

Secrets management isn't a product you buy once — it's a set of habits that make leaking a secret hard and recovering from one fast. Here's the practical version.

The one rule: secrets never touch source code

If a credential is in a file you commit, it's compromised the moment that repo is cloned, forked, or leaked — and rewriting git history rarely fully erases it. So the entire game is keeping secrets out of the code and out of the repo.

Start with a .gitignore and a .dockerignore that exclude them, and commit a .env.example with empty placeholders so contributors know what's needed without seeing real values.

# .gitignore
.env
*.pem
*.key
**/secrets*
Enter fullscreen mode Exit fullscreen mode

Level 1: environment variables (the floor, not the ceiling)

The minimum viable approach: load secrets from the environment at runtime, never from a committed file.

import os
DB_PASSWORD = os.environ["DB_PASSWORD"]   # fail loudly if missing
Enter fullscreen mode Exit fullscreen mode

This is fine for small apps, but env vars have real limits: they leak through crash dumps, child processes, and /proc; they're hard to rotate; and there's no audit trail. Treat them as a starting point.

Level 2: a real secret manager

For anything production, use a dedicated secret store — HashiCorp Vault, AWS Secrets Manager, GCP Secret Manager, Azure Key Vault, or your platform's built-in store. The app authenticates with a short-lived identity and fetches secrets at startup or on demand.

import boto3, json
def get_secret(name: str) -> dict:
    client = boto3.client("secretsmanager")
    return json.loads(client.get_secret_value(SecretId=name)["SecretString"])
Enter fullscreen mode Exit fullscreen mode

What you gain over plain env vars: centralized storage, access control per identity, an audit log of who read what, and rotation support.

Rotate on a schedule, not after a breach

A secret that never changes is a secret that's one leak away from a long, quiet compromise. Rotate credentials regularly and automatically. The pattern that makes rotation painless is two active versions at once: issue the new secret, let both work during an overlap window, deploy, then retire the old one. No big-bang cutover, no downtime.

Prefer short-lived credentials over long-lived keys

The best secret is one that expires on its own. Where you can, replace static API keys with short-lived tokens: cloud IAM roles, OIDC workload identity, and database credentials minted on demand with a TTL. A token that's valid for fifteen minutes is far less valuable to steal than a key that's valid forever.

Scan for leaks before they ship

Add automated secret detection so a hardcoded key is caught in review, not in production. Run a scanner as a pre-commit hook and in CI.

# pre-commit / CI
gitleaks detect --no-banner
# or: trufflehog, detect-secrets
Enter fullscreen mode Exit fullscreen mode

Pre-commit catches it on the developer's machine; CI catches what slipped past. Use both — defense in depth costs almost nothing here.

When a secret leaks: revoke first, investigate second

Speed beats elegance. The moment you suspect exposure:

  1. Revoke/rotate the secret immediately. A removed commit is still public; assume it's compromised.
  2. Issue a replacement through your secret manager.
  3. Check the audit logs for use you didn't expect.
  4. Then do the post-mortem — how it leaked, and which guardrail would have caught it.

The instinct to "quietly remove the commit and hope" is exactly wrong. A leaked key is compromised; treat it that way.

The checklist

Secrets out of code and git? ✅ Real secret manager in production? ✅ Rotation automated with an overlap window? ✅ Short-lived credentials where possible? ✅ Leak scanning in pre-commit and CI? ✅ A revoke-first incident plan? ✅ Six yeses and the "key in a screenshot" disaster mostly can't happen to you.

If you'd rather adopt this as a ready-made setup than assemble it piece by piece, the Secrets Management Guide packages the patterns, config templates, rotation runbooks, and leak-scanning hooks so your team standardizes on the safe path.

Bottom line

You can't prevent every mistake, but you can make the safe way the easy way and the unsafe way loud. Keep secrets out of the repo, manage them centrally, rotate them automatically, and rehearse revocation — and a leaked credential becomes a non-event instead of a breach.

Top comments (0)