secret-scanner

Scans the full git history of a repository for leaked secrets, API keys, tokens, and credentials. Triggered when a user asks to audit commits for exposed credentials, run a pre-publish security check, or scan git history for sensitive data. Produces a severity-ranked findings table with remediation commands. Read-only — never modifies git history automatically.

Secret Scanner

Scan the entire git history of a repository for leaked secrets, credentials, and sensitive tokens.

When to Trigger

  • User asks to scan for secrets or leaked keys
  • User wants to check git history for exposed credentials
  • User requests a pre-publish or open-source readiness security check
  • User asks to audit commits before making a private repo public

Scan Methodology

Step 1: Extract All Historical Diffs

Do NOT scan only the working tree. Secrets may exist in deleted files or amended commits.

# Get all diffs across entire history (all branches, all commits)
git log -p --all --diff-filter=ACMR --no-color

For targeted scanning of specific branches:

git log -p <branch> --no-color

For scanning only added files (initial introductions of secrets):

git log --all --diff-filter=A --name-only --pretty=format:"%H %ai"

Step 2: Scan Each Diff for Secret Patterns

Apply regex patterns against every + line (additions) in every diff hunk.

Secret Patterns

CRITICAL Severity

ProviderPattern
AWS Key IDAKIA[0-9A-Z]{16}
AWS Secretaws_secret_access_key\s*[:=]\s*['"]?[A-Za-z0-9/+=]{40}
GitHub PATghp_[0-9a-zA-Z]{36}
GitHub OAuthgho_[0-9a-zA-Z]{36}
GitHub Finegithub_pat_[0-9a-zA-Z_]{82}
Stripe Livesk_live_[0-9a-zA-Z]{24,}
Stripe Restrictedrk_live_[0-9a-zA-Z]{24,}
Private Key-----BEGIN (RSA|EC|DSA )?PRIVATE KEY-----

HIGH Severity

ProviderPattern
Sentry Authsntryu_[0-9a-f]{64}
Slack Tokenxox[bpors]-[0-9a-zA-Z-]{10,}
Vercel Token[A-Za-z0-9]{24} (in context of VERCEL_TOKEN or header)
SendGridSG\.[0-9A-Za-z_-]{22}\.[0-9A-Za-z_-]{43}
TwilioSK[0-9a-fA-F]{32}
Supabase KeyeyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9\.[A-Za-z0-9_-]+

MEDIUM Severity

TypePattern
Generic passwordpassword\s*[:=]\s*['"][^'"]{8,}['"]
Generic secretsecret\s*[:=]\s*['"][^'"]{8,}['"]
Generic tokentoken\s*[:=]\s*['"][^'"]{16,}['"]
Connection string(mongodb\+srv|postgres|mysql):\/\/[^\s'"]+
Base64 blob[A-Za-z0-9+/=]{40,} (contextual — only flag when near key/token/secret keywords)

Output Format

Present findings as a markdown table sorted by severity:

| # | Severity | Commit     | Date       | File                  | Pattern         | Snippet (masked) |
|---|----------|------------|------------|-----------------------|-----------------|------------------|
| 1 | CRITICAL | a1b2c3d    | 2025-03-15 | src/config.ts         | AWS Key ID      | AKIA****XXXX     |
| 2 | CRITICAL | e4f5g6h    | 2025-02-01 | .env                  | Stripe Live Key | sk_live_****     |
| 3 | HIGH     | i7j8k9l    | 2025-01-20 | lib/sentry.js         | Sentry Auth     | sntryu_****      |
| 4 | MEDIUM   | m0n1o2p    | 2024-12-10 | docker-compose.yml    | Generic password| ********         |

Always mask the middle portion of any found secret. Never display full credentials in output.

Remediation Guidance

For each finding, provide:

1. Credential Rotation (IMMEDIATE)

CRITICAL: Rotate ALL found credentials immediately.
- AWS: IAM Console > Security Credentials > Create New Access Key > Deactivate Old
- GitHub: Settings > Developer Settings > Personal Access Tokens > Regenerate
- Stripe: Dashboard > Developers > API Keys > Roll Key
- Sentry: Settings > Auth Tokens > Revoke & Create New

2. Remove from Git History

Use git filter-repo (NOT git filter-branch which is deprecated):

# Install if needed
pip install git-filter-repo

# Remove a specific file from all history
git filter-repo --invert-paths --path <file-path>

# Replace a specific string across all history
git filter-repo --replace-text <(echo 'AKIA1234567890ABCDEF==>REDACTED')

3. Force Push (Required After History Rewrite)

# WARNING: This rewrites shared history. Coordinate with all collaborators.
git push --force --all
git push --force --tags

Warn the user explicitly:

  • Force-push is required after filter-repo — this rewrites ALL commit SHAs
  • All collaborators must re-clone or git fetch --all && git reset --hard origin/<branch>
  • GitHub/GitLab cached views may still show old commits for ~24 hours

4. Prevent Future Leaks

Recommend adding a .gitignore entry and a pre-commit hook:

# .gitignore additions
.env
.env.local
.env.*.local
*.pem
*.key

# Pre-commit hook (save as .git/hooks/pre-commit)
#!/bin/bash
if git diff --cached | grep -qE 'AKIA|sk_live_|ghp_|-----BEGIN.*PRIVATE KEY'; then
  echo "ERROR: Potential secret detected in staged changes. Aborting commit."
  exit 1
fi

Safety Rules

  1. Read-only scan — never modify git history, files, or configuration automatically
  2. Always show findings first — let the user decide what to remediate
  3. Mask secrets in output — never display full credentials, even in tool output
  4. No network calls — scan is entirely local, no data leaves the machine
  5. Confirm before filter-repo — if the user asks to remediate, confirm the exact commands before execution