secret-history
v1.1.0
Published
Scan your entire git history for secrets and tokens that were committed and later deleted — but still live in history
Downloads
20
Maintainers
Readme
Why this matters
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.
Install
npm install -g secret-historyor run instantly with no install:
npx secret-historyDemo
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.Usage
# 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 --helpWhat it detects
| 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= |
What it shows
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.
How it works
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 outputMemory efficient: history is streamed line-by-line via
readline— works on repos with hundreds of thousands of commits without running out of memory.
What to do when you find something
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.
Requirements
| | |
|---|---|
| Node.js | >= 18 |
| Git | Installed and on your PATH (git log is used internally) |
| Location | Must run from inside a git repository |
FAQ
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.
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.
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.
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.
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
Author
Made by Rakesh Bisht
