Lesson 10 / 31

How Secrets Leak

Identify the common ways API keys and passwords leak and explain why deleting a committed secret is not enough.

By · 15 years in web development

Secrets travel further than you think

A secret is any value that grants access: API keys, database passwords, cloud access keys, private keys, OAuth client secrets, webhook signing keys. They leak in predictable ways: hard-coded in source, committed in a .env file, printed in CI logs, baked into a container image layer, pasted into a ticket or chat, or stored in a frontend bundle that every visitor downloads. The most misunderstood case is Git. When you delete a secret in a new commit, it still exists in history, and every clone and fork already has a copy. Automated bots scan public repositories continuously, so a leaked cloud key can be abused within minutes. The correct response to a leaked secret is therefore always the same order: revoke and rotate it first, check access logs for misuse, then clean history if needed. Rewriting history alone does not make a leaked key safe.

The life of a secret

A safe secret lifecycle runs from creation in a secret store, to injection at runtime, to regular rotation, to revocation when it is no longer needed or has leaked.

Four connected stages: create in a store, inject at runtime, rotate, revoke.
Figure 4.1: create -> inject at runtime -> rotate -> revoke.

Proving the secret is still in history

Deleting the line does not delete the past. git log -p shows the old diff.

git init -q demo && cd demo
git config user.email dev@example.com && git config user.name dev
echo 'API_KEY=demo-not-a-real-key-123' > .env
git add .env && git commit -qm "add config"
git rm -q .env && git commit -qm "remove secret"
test -e .env || echo ".env is gone from the working tree"
git log -p --all | grep 'API_KEY'

Output:

.env is gone from the working tree
-API_KEY=demo-not-a-real-key-123
+API_KEY=demo-not-a-real-key-123

Docker layers remember too

COPY .env . followed by RUN rm .env still leaves the file in an earlier image layer. Use build secrets (RUN --mount=type=secret) and a .dockerignore instead.

Quick check: You notice a cloud access key was pushed to a public repository an hour ago. What should you do first?

  • Rewrite Git history to remove it
  • Revoke and rotate the key, then review its usage logs
  • Make the repository private and continue
  • Add the file to .gitignore
Answer

Revoke and rotate the key, then review its usage logs — Once public, assume it is compromised. Revoking stops abuse; history cleanup and prevention come after.