You just committed your .env file with production database credentials to GitHub. Your stomach drops. You quickly delete the file, commit again, and breathe a sigh of relief.
But you're not safe. Not even close.
Those credentials are still in your git history, visible to anyone who knows where to look. Worse, even after you rewrite history to remove them, the damage might already be done.
Here's what actually works when you leak secrets to git.
Why deleting the file isn't enough
When you commit a file to git and then delete it, the file still exists in your repository's history. Anyone can checkout an old commit or browse the history on GitHub to see it.
This is a common mistake. I see it all the time - developers think deleting sensitive files in a new commit fixes the problem. It doesn't.
The tool: git-filter-repo
git-filter-repo is the modern tool for rewriting git history. It replaced the old git filter-branch command, which was slow and error-prone.
Install it:
Removing secrets from git history
Let's say you accidentally committed a file called .env with AWS credentials. Here's how to remove it completely from your repository's history:
Step 1: Back up your repository
Before you rewrite history, make a backup. This is not optional.
Step 2: Remove the file from history
The --invert-paths flag means "remove this path" instead of "keep only this path".
Step 3: Force push to remote
Why this STILL isn't enough
Here's the part most articles don't tell you: rewriting git history doesn't actually delete your secrets.
Even after you force push, your leaked credentials might still be exposed in:
1. GitHub/GitLab cache
GitHub caches repository data. Your old commits with secrets might still be accessible via direct commit URLs for hours or days.
2. Forks of your repository
If anyone forked your repo before you rewrote history, they still have the original history with your secrets.
3. Pull requests
If you opened pull requests from branches containing secrets, those secrets are visible in the PR diff - even after you rewrite history on the main branch.
4. Local clones
Anyone who cloned your repository before the rewrite has the complete history with your secrets on their machine.
5. CI/CD logs
Your secrets might be printed in CI build logs, deployment logs, or error messages.
6. The secrets themselves are already compromised
This is the big one: the moment your credentials hit a public repository, you should assume they're compromised. Bots scan GitHub for secrets in real-time and harvest them within minutes.
What you actually need to do
Here's the complete checklist when you leak secrets:
Immediate actions (do these first)
-
Rotate the credentials immediately - Generate new API keys, database passwords, tokens, etc. Do this before anything else.
-
Revoke the old credentials - Don't just create new ones, explicitly revoke/delete the leaked ones.
-
Check for unauthorized access - Review access logs, API usage, database connections, AWS CloudTrail, etc. See if anyone used your leaked credentials.
Clean up git history
-
Use git-filter-repo to remove secrets from history (shown above)
-
Contact GitHub support - Ask them to purge cached commits from their servers. They have a process for this:
- Go to https://support.github.com/contact
- Select "Remove sensitive data"
- Provide commit SHAs containing secrets
-
Delete all forks - Contact anyone who forked your repository and ask them to delete their fork or update from your cleaned history.
-
Notify all contributors - Tell anyone with a local clone to delete their copy and re-clone from the cleaned repository.
Prevent it from happening again
- Add secrets to .gitignore immediately:
- Use a secrets scanner - Install a pre-commit hook to catch secrets before they're committed:
- Set up GitHub secret scanning - Enable secret scanning in your repository settings. GitHub will alert you if it detects leaked credentials.
Real example: AWS keys leaked
Here's what a real AWS key leak response looks like:
Advanced: remove specific strings instead of files
Sometimes secrets are hardcoded in source files rather than separate credential files. You can use git-filter-repo to remove specific strings:
Takeaways
-
Rewriting git history is necessary but not sufficient - It removes secrets from your repository but doesn't undo the exposure.
-
Rotate credentials first - This is the only thing that actually makes leaked secrets useless. Do it immediately.
-
Assume breach - Once secrets hit a public repo, assume they're compromised. Check logs for unauthorized access.
-
Prevention is everything - Use .gitignore, pre-commit hooks, and secret scanners to prevent leaks in the first place.
-
git-filter-repo is fast - Unlike old tools, it can rewrite large repository histories in seconds, not hours.
The hard truth
If you're reading this after leaking production credentials, your priority isn't git history - it's rotating those credentials and checking for unauthorized access.
The git cleanup is important for preventing future exposure, but the real security work happens outside of git: in your AWS console, database settings, API dashboards, and access logs.
Don't let a clean git history give you false confidence. The secrets were public. Act accordingly.