Secrets, .env & push protection
Keep secrets out of Git
Lesson 19 of 20 · 12 min · Module 6: Safe releases and the capstone
Passwords, API keys and tokens must never be committed. Anyone who can read a repository can read every version of every file in it, forever.
Start this lesson →Free. No installation: you write and run the code in your browser, and it is checked automatically.
By the end, you’ll be able to…
- Explain why committed secrets stay exposed
- Get past push protection by removing the secret
- Keep secrets in ignored files with a committed example
The idea
Keep secrets in a file such as .env that Git ignores, and commit a .env.example with the same names and empty values so others know what to fill in. GitHub's push protection blocks pushes that contain known secret formats. Deleting the file in a new commit does not help, because the old commit still holds the secret: remove it from the commits you are about to push, for example with git reset. If a secret was ever pushed anywhere, treat it as leaked: revoke it and create a new one.
git reset HEAD~1
echo ".env" >> .gitignore
echo "CTPAY_SECRET_KEY=" > .env.example
01History never forgets
Every version of every file stays in the history, and every clone has a full copy. Deleting a secret in a later commit hides it from the latest version only. That is why secrets must never be committed at all.
02Push protection catches known secrets
GitHub scans what you push for known key formats and refuses the push. To get past it, remove the secret from the commits you are pushing. Here the commit is still local, so undo it with git reset and commit again without .env.
git pushEnumerating objects: 5, done.
Counting objects: 100% (5/5), done.
Delta compression using up to 8 threads
Compressing objects: 100% (4/4), done.
Writing objects: 100% (4/4), 461 bytes | 461.00 KiB/s, done.
Total 4 (delta 1), reused 0 (delta 0), pack-reused 0 (from 0)
remote: error: GH013: Repository rule violations found for refs/heads/main.
remote:
remote: - GITHUB PUSH PROTECTION
remote: —————————————————————————————————————————
remote: Resolve the following violations before pushing again
remote:
remote: - Push cannot contain secrets
remote:
remote:
remote: (?) Learn how to resolve a blocked push
remote: https://docs.github.com/code-security/secret-scanning/working-with-secret-scanning-and-push-protection/working-with-push-protection-from-the-command-line#resolving-a-blocked-push
remote:
remote:
remote: —— Code Temper Pay Secret Key ————————————————————————
remote: locations:
remote: - commit: 83045e22a2ee2ae496447673c2002053a41021ac
remote: path: .env:1
remote:
remote: (?) To push, remove secret from commit(s).
remote:
To https://github.com/learner/website.git
! [remote rejected] main -> main (push declined due to repository rule violations)
error: failed to push some refs to 'https://github.com/learner/website.git'03Ignore the real file, share an example
.env holds the real values on your computer and is ignored. .env.example lists the same names with empty values, so teammates know what to fill in.
git reset HEAD~1
echo ".env" >> .gitignore
echo "CTPAY_SECRET_KEY=" > .env.example
git status --short?? .env.example
?? .gitignore
?? checkout.jsYour turn
Add online payments accidentally includes .env, which holds a secret key. Push it and read how push protection blocks it. Then undo the commit but keep your files with git reset HEAD~1, add .env to .gitignore, and create .env.example containing CTPAY_SECRET_KEY= with no value. Commit checkout.js, .gitignore and .env.example as Add online payments, and push.What the checks look for
- Push protection blocks the first push
- The payments commit is on GitHub
- The secret key never reached GitHub
- .env is ignored, untracked, and still on your computer
- .env.example is committed without a value
- Everything is committed and pushed
Take this with you
Keep secrets in ignored files, commit only examples, and revoke anything that leaked.
Go a little further
Run git log --all --oneline -- .env after the reset: no commit contains .env any more, which is exactly why the push now succeeds.