The key is already public: what to do after you commit a secret
Deleting the commit is not the fix. Revoke the key first, check who used it, then clean up and put a scanner in front of the next push.
It happens to everybody once. A .env file or a hard-coded key goes into a commit, the commit goes to a remote, and a second later you notice. The instinct is to delete the commit. That feels like fixing it. It is not.
Assume it was read#
Automated scanners watch public repositories all the time, for exactly this. A key that has been in a public repository, even briefly, has to be treated as read. Force-pushing the history away does not take the key back from forks, clones, caches or anybody who was already looking.
So the order is fixed, and the cleanup comes last:
- Revoke or rotate the key. At the provider, today, before anything else. A new key makes the old one worthless, and that is the only step that really fixes it.
- Look for use. Most providers show activity per key. Check the window between the commit and the revocation for anything you do not recognise.
- Replace it everywhere it ran. New key into the secret store, the deploy config and the CI settings, not back into the repository.
- Then clean the history, with a tool made for it such as
git filter-repo, so that the next person who clones does not find it. This is hygiene. It does not undo step 1. - Put a scanner in front of the next push.
What a scanner finds#
Our small scanner, secscan, looks for well known key shapes and redacts what it prints by default. We ran it on a folder holding the example access key that AWS uses in its own documentation, which is public and not a real credential:
[critical] aws_access_key AKIA...(12 chars)...MPLE
./.env:1:19
[critical] aws_access_key AKIA...(12 chars)...MPLE
./app.js:1:12
2 findings (2 critical)It exits with a non-zero code when it finds something, so it can stand in a pre-commit hook or a CI step and stop a push. Other scanners do the same job, gitleaks and trufflehog among them. Which one you use matters much less than using one before the push, not after.
Habits that make it rarer#
- Keep
.envin.gitignorefrom the first commit of the project, not the tenth. - Commit a
.env.examplewith fake values, so the shape is documented and the real file never needs to travel. - Prefer short-lived credentials where the provider offers them. A key that expires in an hour is a small leak.
- Give each key the least it needs. A key that can only read one bucket is a different incident from one that can do anything.
The embarrassing part is not the mistake. It is finding out three weeks later from a bill. Revoke first.