07 · Best practice
Never commit a secret
.env.example in repo, .env in .gitignore, MCP tokens loaded from the shell.
The fastest way to ruin a Friday is realizing a GitHub token is in your last commit. Easy to forget when you're moving fast: .env is your friend, but only if you also .gitignore it. The next level is moving secrets out of .env entirely into a vault — Doppler, Infisical, or HashiCorp Vault — so every machine pulls the same source of truth and rotations don't require a Slack DM.
The setup that works
.env.example— the template. Lives in the repo. Contains keys, never values..env/.env.local— your actual values. Listed in.gitignorefrom day one.mcp.json.example— the MCP config template. Values come from${ENV_VAR}references that resolve from your shell, not from a checked-in.mcp.json.
How to do it
Copy .env.example and .gitignore from this repo. Make sure .env, .env.local, .env.* are gitignored. Allowlist .env.example so the template stays committed.
Copy .gitleaks.toml from this repo. It extends the gitleaks defaults with rules for Supabase, Resend, and GitHub PATs.
Install gitleaks and wire it as a pre-commit hook — it catches the slips.
brew install gitleaks # macOS
gitleaks detect --source . --no-banner # scan once
gitleaks protect --staged --no-banner # run from .git/hooks/pre-commit
Past the prototype phase? Pick a vault:
- Doppler — easiest UX, generous free tier.
- Infisical — open source, self-hostable.
- HashiCorp Vault — enterprise.
When the model asks for a token
It shouldn't. If Claude asks you to paste a token into chat, that token is now in the conversation history and any future tool that processes the transcript. Refuse. Set it in your shell environment and let the MCP server read it.
If you do leak a key
- Rotate immediately. Don't wait. The old key is burned the moment you push.
- Audit history.
git log -p -- path/to/fileshows past commits. - Decide on scrubbing. For fresh repos, rotation alone is enough (the old key is dead). For long-lived repos with the leak deep in history, consider
git filter-repo. - Tell the team. Don't hide it. Make the rotation a learning moment.
A revoked token in a public commit is harmless; a leaked active token isn't, even after you force-push. The order matters: rotate, then rewrite history.
Anti-patterns
.envcommitted once and "I'll rotate the key later." Rotate it now.- Pasting an API key into a chat with Claude. It's in the conversation context now.
- Skipping the pre-commit hook because "I'm careful." Everyone is careful. Hooks catch the one time you weren't.
- Storing secrets in
CLAUDE.md"for context." Don't.