Juicy Shop

← All lessons

Secrets Management

ConfigurationA05:2021 – Security Misconfigurationintermediate9 min

API keys, database passwords, and signing keys leak constantly through source code, logs, and git history. Learn where secrets belong, how to rotate them, and why 'it's in a private repo' is not protection.

Why hardcoded secrets are a breach waiting to happen

A secret committed to source code is exposed to everyone with repository access, every CI job, every fork, and — once pushed — every copy of the git history forever. Private repositories get cloned to laptops, leaked in screenshots, and accidentally made public. Treat any secret that has ever touched source control as compromised: the only real fix is rotation, not deletion of the line.

Where secrets actually belong

Keep secrets out of code and configuration files entirely. Inject them at runtime through environment variables for local and simple deployments, and through a dedicated secret manager (Vault, AWS/GCP Secrets Manager, your platform's secret store) for production. The application reads them at startup; they are never written to the repo, the image, or the build logs.

Rotation, scoping, and least privilege

Secrets should be short-lived and narrowly scoped. Prefer short-lived tokens and workload identity over long-lived static keys. Give each credential the minimum permissions it needs, use a distinct secret per environment, and have a tested rotation process so that revoking and reissuing a leaked key is routine — not an emergency that nobody knows how to run.

Stop secrets leaking through the side doors

Secrets escape through more than source code: application logs that dump request bodies or config, error messages and stack traces, client-side bundles, and verbose debug output. Never log secrets, scrub them from telemetry, keep them server-side, and run automated secret scanning (pre-commit hooks and CI) so a key is caught before it is ever pushed.

Insecure vs secure

✗ insecure
const stripe = new Stripe(
  "sk_live_51H8xQ2eZvKYlo2C0a9f3kPq..." // hardcoded!
);
console.log("using key", process.env.DB_PASSWORD);

The live key is committed to source forever, and the database password is written to logs where anyone with log access can read it.

✓ secure
const key = process.env.STRIPE_SECRET_KEY;
if (!key) throw new Error("STRIPE_SECRET_KEY is not set");
const stripe = new Stripe(key);
// never log secrets

The secret is injected from the environment (or a secret manager), validated at startup, and never written to logs.

Key takeaways

  • Any secret committed to source control must be rotated, not just removed.
  • Inject secrets via environment variables or a secret manager at runtime.
  • Scope credentials to least privilege and use a distinct secret per environment.
  • Prefer short-lived tokens and have a tested rotation process.
  • Never log secrets; run automated secret scanning in pre-commit and CI.

Knowledge check

Further reading