← Catalog Matrix
DevOps

Purging Exposed Secrets and API Keys Permanently from Git History

A critical security recovery blueprint using BFG Repo-Cleaner and native Git filter-branch mechanics to obliterate tracked credentials from past commit graphs.

Accidentally committing configuration environments (.env) or secret API tokens directly into a public Git ledger happens to even veteran engineers. Simply executing git rm .env and pushing a new commit is an amateur mistake—the file remains fully visible to bots and bad actors who can easily traverse your past commit tree history.

To mitigate the exposure before your infrastructure is compromised, you must completely rewrite the repository's historical graph.

The History Scrubbing Protocol

To safely and permanently excise tracked credentials without completely corrupting your existing codebase structure, your pipeline must follow an explicit execution order:

  1. Upstream Token Rotation: Treat any exposed credential as instantly compromised. Rotate your keys immediately before running code-level alterations.
  2. Commit Blob Purging: You must destroy the internal pointer references to the file hashes across every single historical commit object, tag, and branch.
  3. Garbage Collection Optimization: Git retains dead files in an internal loose objects cache. You must force-expire the reflogs and run a violent garbage collection sequence to permanently reclaim the space and delete the file contents locally before pushing.

The security automation blueprint below details how to execute these deep operations using the ultra-fast modern alternative to legacy filter-branch commands: BFG Repo-Cleaner.

Git History Cleansing Shell Automation Blueprint

#!/bin/bash

================================================================

STRATEGY 1: FAST REPO PURGING VIA BFG REPO-CLEANER (RECOMMENDED)

================================================================

Step 1: Clone a fresh, naked "mirror" copy of your repository to an isolated workspace

Replace with your specific repository address

git clone --mirror git@github.com:username/compromised-repo.git cd compromised-repo.git

echo "[Analyzing Repository] Commencing BFG automated history scrubbing sequence..."

Download BFG repo-cleaner tool jar if not present locally, or use a package manager:

sudo apt install bfg OR brew install bfg

ACTION A: Purge a specific file (like your .env file) completely across all past commits

bfg --delete-files .env

ACTION B: Alternatively, to replace text arrays (like an explicit API Key string)

across all files in history, place the key inside 'passwords.txt' and run:

bfg --replace-text passwords.txt

echo "[Local Refactor Complete] Stripping dead reflogs and forcing garbage collection..."

BFG optimizes the history graph, but Git's internal engine requires an explicit

garbage collection cycle to completely drop the loose objects from disk storage blocks.

git reflog expire --expire=now --all && git gc --prune=now --aggressive

echo "[Pushing Structural Modifications] Rewriting the upstream central mirror repository..."

Force push the rewritten history back up to your central provider (GitHub, GitLab, Bitbucket)

WARNING: This overwrites history. Ensure your team pulls down a fresh clone after this action.

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

cd .. rm -rf compromised-repo.git echo "Success: Historical ledger successfully sanitized."

==================================================================

STRATEGY 2: BARE-METAL GIT FALLBACK (IF JAVA/BFG IS NOT AVAILABLE)

==================================================================

If you cannot run BFG, copy and execute this native Git command string within a

standard non-mirror clone of your repository to recursively strip a file:

read -r -d '' NATIVE_GIT_FALLBACK << 'EOF' git filter-branch --force --index-filter \ "git rm --cached --ignore-unmatch .env" \ --prune-empty --tag-name-filter cat -- --all

Force push the native execution alterations

git push origin --force --all EOF