Skip to main content

How to Clean Up Exposed Credentials in Git with git-filter-repo and Rotate Tokens

Rogelio Guerra Riverón
Author
Rogelio Guerra Riverón
Building my own web infrastructure from scratch. Here I document each step: servers, networks, containers and everything that comes along.

The Real Problem
#

I recently realized I had pushed a .env file with API credentials to a private repository. Even though it was private, that’s no excuse. A compromised access, a repository that becomes public, or simply a security audit would have exposed my tokens. I learned that I can’t rely on deleting files in subsequent commits—Git keeps all the history.

Why git-filter-repo
#

Years ago I would have used git filter-branch, but it’s slow and error-prone. git-filter-repo is the modern tool recommended by Git maintainers. It’s fast, precise, and has better options for this job.

Installation
#

On my Debian server:

apt-get install git-filter-repo

Or with pip:

pip3 install git-filter-repo

Step 1: Identify the Damage
#

First, I need to know which commits contain credentials. I search for suspicious patterns:

git log --all --oneline | head -20
git log -p --all | grep -i "token\|password\|api_key" | head -10

I also review what sensitive files are in the history:

git log --all --full-history -- ".env"
git log --all --full-history -- "config.yml"

In my case, I found that .env had been committed 3 times and a credentials.json file in 2.

Step 2: Make a Backup
#

I never do this without a backup:

cd /path/to/my/repo
git clone --mirror . backup-mirror.git

If something goes wrong, I have a complete copy of the repository with all its history.

Step 3: Clean Specific Files
#

I run git-filter-repo to remove the sensitive files from the entire history:

git-filter-repo --invert-paths --path .env --path credentials.json

The --invert-paths parameter means it keeps everything EXCEPT what I specify. This is the opposite of what it seems, but it works perfectly.

The process takes a few seconds and rewrites all the history. At the end, I see:

Processed 47 commits
New history has 47 commits

Step 4: Force Push (Carefully)
#

Since I’ve rewritten the history, I need to do a force push. On a home server where I’m the only dev, it’s safe:

git push origin --force --all
git push origin --force --tags

If it’s a shared repository, I coordinate with the team so everyone does git reset --hard origin/main afterward.

Step 5: Rotate Compromised Credentials
#

The credentials that were in Git are no longer there, but I must assume they were compromised. I rotate all tokens:

  1. API Keys: I revoke the old ones in the API panel and generate new ones
  2. Passwords: I change the password for any service that used those credentials
  3. Database Tokens: I regenerate database credentials
  4. SSH Keys: If they were exposed, I generate new pairs

I document these changes in a private file (not in Git):

2026-05-19 - Rotación de credenciales post-exposición
- API key antigua: revocada, nueva generada
- Token DB: regenerado
- Contraseña servicio X: cambiada

Step 6: Future Prevention
#

I add rules to .gitignore (now it’s clean):

.env
.env.local
credentials.json
secrets/

I also configure a pre-commit hook to detect dangerous patterns:

git config core.hooksPath .githooks

And I create .githooks/pre-commit:

#!/bin/bash
if git diff --cached | grep -iE "(password|token|api_key|secret)" && \
   ! git diff --cached | grep ".gitignore"; then
    echo "⚠️ Posible credencial detectada. Abortando."
    exit 1
fi

Conclusion
#

The cleanup takes 10 minutes. Credential rotation, another while. But it’s time well spent. On a home server, I have no excuse for being negligent with secrets. Now I use environment variables and local files that never go into Git.

Lesson learned: Secrets never go in version control, not even “private”. Period.

Recommended Equipment#

  • YubiKey 5 NFC — Physical security key for SSH and GitLab — eliminates the risk of stolen tokens
  • 2TB External Hard Drive — Backup repositories before destructive operations like git-filter-repo

Affiliate links. No extra cost to you.