I Leaked My AWS Keys to GitHub. Rewriting Git History Wasn't Enough

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:

# macOS
brew install git-filter-repo

# Linux
pip3 install git-filter-repo

# Verify installation
git filter-repo --version

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.

# Clone your repo to a backup location
git clone --mirror [email protected]:yourname/yourrepo.git yourrepo-backup

Step 2: Remove the file from history

# Navigate to your repository
cd yourrepo

# Remove the .env file from all commits
git filter-repo --path .env --invert-paths

# This rewrites every commit in your history to exclude .env

The --invert-paths flag means "remove this path" instead of "keep only this path".

Step 3: Force push to remote

# Add your remote back (git-filter-repo removes remotes by default)
git remote add origin [email protected]:yourname/yourrepo.git

# Force push to overwrite history
git push origin --force --all
git push origin --force --tags

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)

  1. Rotate the credentials immediately - Generate new API keys, database passwords, tokens, etc. Do this before anything else.

  2. Revoke the old credentials - Don't just create new ones, explicitly revoke/delete the leaked ones.

  3. 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

  1. Use git-filter-repo to remove secrets from history (shown above)

  2. Contact GitHub support - Ask them to purge cached commits from their servers. They have a process for this:

  3. Delete all forks - Contact anyone who forked your repository and ask them to delete their fork or update from your cleaned history.

  4. 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

  1. Add secrets to .gitignore immediately:
# Add to .gitignore
.env
.env.local
.env.*.local
credentials.json
secrets.yaml
config/secrets.yml
*.pem
*.key
  1. Use a secrets scanner - Install a pre-commit hook to catch secrets before they're committed:
# Install gitleaks
brew install gitleaks

# Run it on your repo
gitleaks detect --source . --verbose

# Add it as a pre-commit hook
gitleaks protect --staged --verbose
  1. 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:

# 1. Immediately disable the leaked credentials in AWS IAM console
# Go to IAM → Users → [user] → Security credentials → Deactivate

# 2. Check AWS CloudTrail for unauthorized access
aws cloudtrail lookup-events \
--lookup-attributes AttributeKey=AccessKeyId,AttributeValue=AKIA... \
--max-results 50

# 3. Remove from git history
git filter-repo --path config/aws-credentials.yaml --invert-paths

# 4. Force push
git remote add origin [email protected]:yourname/yourrepo.git
git push origin --force --all

# 5. Generate new credentials in AWS IAM console
# 6. Update your production systems with new credentials
# 7. Delete the old credentials completely from AWS

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:

# Create a file with strings to remove (one per line)
cat > secrets.txt << EOF
AKIAIOSFODNN7EXAMPLE
wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
postgres://user:pass123@localhost:5432/db
EOF

# Remove these strings from all files in history
git filter-repo --replace-text secrets.txt

# This replaces the strings with "***REMOVED***" in all commits

Takeaways

  1. Rewriting git history is necessary but not sufficient - It removes secrets from your repository but doesn't undo the exposure.

  2. Rotate credentials first - This is the only thing that actually makes leaked secrets useless. Do it immediately.

  3. Assume breach - Once secrets hit a public repo, assume they're compromised. Check logs for unauthorized access.

  4. Prevention is everything - Use .gitignore, pre-commit hooks, and secret scanners to prevent leaks in the first place.

  5. 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.

·share on