Secrets you deleted are still in your git history.
Scans your entire git commit history for accidentally committed secrets, tokens,
and credentials — even ones that were removed long ago but still live in old commits.
Deleting a secret from your codebase does not remove it from git history. Anyone who can clone your repo can run git log -p and read every secret you've ever committed. This tool finds them before someone else does.
npm install -g secret-historyor run instantly with no install:
npx secret-history secret-history
Scanned: 1,247 commits (all 1,247 commits)
Found: 2 critical · 1 high · 4 low
⚠ 2 SECRETS STILL IN YOUR CODEBASE
Rotate these credentials immediately.
──────────────────────────────────────────────────────────────
CRITICAL ● AWS Access Key ID
File: config/aws.js
Commit: a3f2c1d8 Jay Smith Mar 04, 2024
Message: add s3 upload support
Value: AKIA************MPLE
Status: ⚠ still in HEAD
··············································
CRITICAL ● Database URL with credentials
File: .env.production
Commit: b7e91a23 Jay Smith Jan 15, 2024
Message: initial setup
Value: post************5432
Status: ⚠ still in HEAD
──────────────────────────────────────────────────────────────
1 secret removed from code but still in git history
These are readable by anyone who clones this repo.
──────────────────────────────────────────────────────────────
HIGH ● GitHub Token
File: scripts/deploy.sh
Commit: c9d12e45 Jay Smith Dec 02, 2023
Message: automate deployment
Value: ghp_****************************4f2a
Status: ✓ removed from code
──────────────────────────────────────────────────────────────
How to purge secrets from history:
Option 1 — git-filter-repo (recommended):
pip install git-filter-repo
git filter-repo --path <file> --invert-paths
Option 2 — BFG Repo Cleaner:
java -jar bfg.jar --delete-files <filename>
https://rtyley.github.io/bfg-repo-cleaner/
After purging, force-push all branches and have collaborators re-clone.
# Scan full history
secret-history
# Scan only the last N commits (faster for large repos)
secret-history --depth 500
secret-history --depth 100
# Help
secret-history --help| Severity | Patterns |
|---|---|
| 🔴 Critical | AWS Access Key & Secret, Private Keys (RSA/EC/DSA/OpenSSH), GitHub Tokens, Stripe Live Keys, Database URLs with credentials |
| 🟠 High | Google API Keys, Slack Tokens, SendGrid API Keys, Twilio Account SIDs, NPM Tokens, Mailchimp API Keys |
| 🟡 Medium | JWT Tokens, .env variable assignments (API_KEY=, SECRET_TOKEN=, etc.) |
| ⚪ Low | Generic quoted assignments — password=, secret=, api_key=, access_token= |
For each finding:
| Field | Description |
|---|---|
| File | The file the secret appeared in |
| Commit | Short hash, author name, and date |
| Message | The commit message for context |
| Value | Redacted preview — e.g. AKIA****MPLE |
| Status | ⚠ still in HEAD (needs rotating) or ✓ removed (needs purging from history) |
Results are grouped: still-exposed secrets first, then secrets only in history. Within each group, sorted by severity.
git log --all -p → stream full patch history (all branches & tags)
↓
parse + lines → only scan lines added in each commit diff
↓
match patterns → 17 regex patterns across 4 severity levels
↓
deduplicate → one finding per (file, pattern, value)
↓
check HEAD → is the secret still present right now?
↓
render → grouped, colored, redacted output
Memory efficient: history is streamed line-by-line via
readline— works on repos with hundreds of thousands of commits without running out of memory.
If the secret is still in HEAD (⚠ still in HEAD)
- Rotate/revoke the credential immediately with the service provider
- Remove it from the codebase
- Purge it from history (see below)
If the secret is only in history (✓ removed)
The file no longer contains it, but the secret is still readable in old commits:
# Option 1 — git-filter-repo (recommended, Python-based)
pip install git-filter-repo
git filter-repo --path <file> --invert-paths
# Option 2 — BFG Repo Cleaner (Java-based)
# Download from: https://rtyley.github.io/bfg-repo-cleaner/
java -jar bfg.jar --delete-files <filename>
# After either option — force-push all branches
git push --force --all
git push --force --tags⚠ After purging history, all collaborators must re-clone the repository. Existing clones still contain the old history.
| Node.js | >= 18 |
| Git | Installed and on your PATH (git log is used internally) |
| Location | Must run from inside a git repository |
Will this find secrets on other branches too?
Yes — secret-history uses git log --all which includes all local branches and tags. If a secret was committed anywhere in the repo's reachable history, it will be found.
It's slow on a large repo
Use --depth to limit the scan to recent commits:
secret-history --depth 200For a full scan, let it run — history is streamed line-by-line so memory usage stays flat regardless of repo size.
Too many false positives from test files
The low severity findings (generic password=, secret= patterns) often fire on test fixtures with placeholder credentials. Focus on critical and high findings first — those use strict, format-specific patterns that rarely produce false positives.
Is the actual secret value stored or transmitted anywhere?
No. secret-history only displays a redacted preview (e.g. AKIA****MPLE) and never writes the raw value to disk or sends it anywhere. Everything runs entirely locally.
I purged the secret — is my repo safe now?
Only if everyone re-clones. Existing clones still have the old history. Also check:
- GitHub/GitLab cached views of the file
- Any forks of the repo
- CI logs that may have printed the secret
Made by Rakesh Bisht