6.8
Keeping Secrets Secret
Why this exists
You're now working across real systems, which means you're handling the things that open them. API keys, tokens, passwords, connection strings.
Leaking one is the mistake with the longest tail in this whole course. Break a page and you fix it in ten minutes. Leak a key and you're rotating credentials, checking access logs, and wondering how long it was out there.
The idea
Secrets live in one place, and it is never the code.
The rule is small. The failure modes are where the lesson is, because they're all things that feel harmless in the moment:
| What people do | Why it bites |
|---|---|
| Paste a key "just to test it" | The test works. The key stays. |
| Commit a config with a real value in it | It's in git history forever, even after you delete it |
| Screenshot a terminal with a token visible | Now it's in Slack, and Slack is searchable |
| Put a key in a filename or a URL | URLs end up in logs, history, and other people's browsers |
Deleting a committed secret does not remove it. This is the one that surprises people. Git keeps history — that's the whole point of it — so a key you committed and then removed is still sitting in the previous commit, and anyone with the repo can read it. The only real fix is to treat that key as burned and rotate it.
Where they should live instead:
- A
.envfile, which is gitignored, containing the real values - A
.env.example, which is committed, containing the names with fake values so the next person knows what's needed - The host's own secret storage for anything deployed
That .env.example pattern is worth the thirty seconds. It documents what a system needs without exposing anything, and it's how you'll know what to ask for when you set something up on a new machine.
Two habits that matter more than the rule.
First: check before every commit. Not just git diff for correctness, as in 5.3 — a specific look for anything that looks like a credential. Long random strings, anything called key, token, secret, password.
Second: when in doubt, rotate. If you're not sure whether a key was exposed, it was. Rotating is fifteen minutes of mild annoyance. Not rotating is a decision to accept a risk you can't measure, and you'll make that decision at the exact moment you're least equipped to.
One thing specific to how you work now: be careful what you paste into a chat. Pasting a config file to ask what's wrong is completely normal and it's also how keys travel. Redact first. Same for screenshots — check what's in the terminal scrollback before you share the window.
Do
- Look at a repo you work in. Is there a
.gitignore? Does it cover.env? - Ask Claude: "Are there any credentials, keys or tokens committed in this repo, including in git history?" Verify what it finds yourself.
- Search history directly:
bash git log -p | grep -inE "api[_-]?key|secret|token|password" | head -20 - If anything real turns up: tell Callum, and treat the key as burned. Do not just delete it.
- Create or fix
.env.example— every variable the project needs, with fake values. - Do the reverse check: look at the last three things you pasted into a chat or shared as a screenshot. Was there anything sensitive in them?
- Write
secrets.md: where secrets live in this system · how you check before committing · what you'd do if one leaked.
Step 6 catches more real exposure than step 3 does. Repos get audited. Chat history and screenshots don't.
Done when
Never do
Never commit a real credential, not even for a minute. Git history is permanent by design. The only fix afterwards is rotation.
Never paste a config file without redacting it. Normal thing to do, most common way keys escape.
Never assume a key is fine because you're not sure it leaked. Not sure means it leaked. Rotate.