Skip to main content

secret-time-machine

"The Past is Not Private"

A Python CLI tool that scans the entire git history of a repository for secrets, API keys, passwords, and tokens — including ones that were "deleted" long ago. git rm does not erase history. Every secret ever committed is still there.

Why this exists

Developers often commit secrets accidentally and then delete them with git rm or a follow-up commit. The secret looks gone from the working tree, but it is permanently embedded in git history. Anyone who clones the repo — now or in the future — can read every commit, including the deleted one.

secret-time-machine time-travels through every commit and every diff to surface those forgotten credentials.

Installation

pip install secret-time-machine

Or from source:

git clone https://github.com/yourusername/secret-time-machine
cd secret-time-machine
pip install -e .

Quick start

# Scan the current directory's git history
secret-time-machine

# Scan a specific repo
secret-time-machine --repo /path/to/repo

# Output JSON for CI pipelines
secret-time-machine --json

# Show full secret values (default is to redact)
secret-time-machine --show-secrets

# Get remediation instructions
secret-time-machine --remediation

All options

Usage: secret-time-machine [OPTIONS]

Options:
  --repo PATH          Path to the git repository to scan.
  --branch TEXT        Scan only commits on this branch (default: all).
  --last N             Scan only the last N commits.
  --additions-only     Only report secrets in addition lines (+ lines).
  --json               Output results as JSON.
  --show-secrets       Show full secret values (default: redact).
  --redact             Explicitly redact secret values (this is the default).
  --remediation        Show instructions for cleaning secrets from history.
  --version            Show the version and exit.
  --help               Show this message and exit.

What it detects

Pattern Severity
AWS Access Key (AKIA...) HIGH
AWS Secret Key HIGH
GitHub Token (ghp_...) HIGH
GitHub OAuth (gho_...) HIGH
OpenAI API Key (sk-...) HIGH
Anthropic API Key (sk-ant-...) HIGH
Stripe Secret Key (sk_live_...) HIGH
Google API Key (AIza...) HIGH
Slack Token (xox...) HIGH
Private Keys (RSA, EC, OPENSSH) HIGH
SendGrid API Key HIGH
HuggingFace Token (hf_...) HIGH
NPM Token (npm_...) HIGH
Database URLs (postgres, mongo, redis) HIGH
Generic Password (password = "...") MEDIUM
Generic Secret (api_key = "...") MEDIUM
JWT Tokens MEDIUM
Heroku API Keys MEDIUM
And more...

Example output

╔══════════════════════════════════════════╗
║         SECRET TIME MACHINE              ║
║      "The Past is Not Private"           ║
╚══════════════════════════════════════════╝

Scanning: /Users/user/myproject
Commits scanned: 1,247 (across all branches)
Time range: 2021-03-14 to 2024-11-22

SECRETS FOUND IN HISTORY: 2

  x OpenAI API Key  HIGH
    Commit:  a4f8c2d  (2023-08-14 by jane@example.com)
    File:    config/settings.py
    Status:  DELETED in commit b9e3f1a — still in history, key may be compromised
    Value:   sk-••••••••••••••••••••••••XKBP

  x AWS Access Key  HIGH
    Commit:  3c7d9a1  (2022-11-30 by bob@example.com)
    File:    deploy/terraform.tf
    Status:  Still present in current codebase!
    Value:   AKIA••••••••••••MNPQ

How it works

  1. Runs git log --all --format="%H %ae %aI" to collect every commit hash across all branches.
  2. For each commit, runs git diff-tree --no-commit-id -p -r {hash} to get the full patch.
  3. Scans every line starting with + (additions) against all secret patterns.
  4. Checks whether each found secret is still present in HEAD or was later deleted.
  5. Reports findings sorted by severity, with optional JSON output for CI integration.

Remediation

Run secret-time-machine --remediation for the full guide. Short version:

  1. Use git filter-repo to purge secrets from history (or BFG Repo Cleaner for large repos).
  2. Force-push the rewritten history.
  3. Rotate every exposed credential immediately.
  4. Add .env files to .gitignore and install pre-commit hooks to prevent future leaks.

CI integration

Use the --json flag and check the exit code. The tool exits with code 1 if any secrets are found, 0 if the history is clean.

# GitHub Actions example
- name: Scan git history for secrets
  run: secret-time-machine --json --additions-only > scan-results.json
  continue-on-error: true

- name: Fail if secrets found
  run: |
    count=$(jq '.summary.total_findings' scan-results.json)
    if [ "$count" -gt 0 ]; then exit 1; fi

Development

# Install dev dependencies
pip install -e ".[dev]"

# Run tests
pytest -v

# Type checking
mypy src/

# Formatting
black .
isort .

Security note

This tool calls git via subprocess with a list of arguments (never shell=True) and uses shlex.quote() for any user-provided paths, preventing shell injection attacks.

License

MIT

Metadata

Release files for secret-time-machine 1.0.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for secret-time-machine 1.0.0
File Size Uploaded
secret_time_machine-1.0.0.tar.gz 21.7 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for secret-time-machine 1.0.0
File Interpreter ABI Platform
secret_time_machine-1.0.0-py3-none-any.whl Python 3 none any Details

Total release size: 38.1 kB

Release files / secret_time_machine-1.0.0.tar.gz

Download URL secret_time_machine-1.0.0.tar.gz
Size 21.7 kB
Tags Source
SHA-256 checksum
How to use checksums
5d623aaf153858db66e07461881afaff3aaec15e14dd029cc5cc7f03f55dc5c7
BLAKE2b-256 checksum
How to use checksums
a5d1664ce572cfb734593a64a51aea563a397245574cdd9e22cce70827b61302
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.13.6

Release files / secret_time_machine-1.0.0-py3-none-any.whl

Download URL secret_time_machine-1.0.0-py3-none-any.whl
Size 16.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
e723dfd7106c1f31e1105a1352cdd496bf97be58829849454972870302b97764
BLAKE2b-256 checksum
How to use checksums
d1884ecd4230c6ce4d900e9512fbd7c3309909783ba5f2de350f57b6022322a8
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.13.6

Release history Release notifications | RSS feed

This release

1.0.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page