A CLI tool to detect leaked secrets in Git repositories
Project description
secretleak
A production-quality CLI tool to detect leaked secrets (API keys, tokens, private keys) in Git repositories.
Features
- Regex rules — 30+ built-in patterns covering AWS, GitHub, Stripe, Google, Slack, Twilio, SendGrid, npm, PyPI, private keys, connection strings, and more
- Shannon entropy heuristic — catches high-entropy strings that don't match a known pattern
- Three scan modes — working tree, staged diff (
git diff --staged), commit range - Three output formats — Rich console table, JSON report, SARIF 2.1.0 (GitHub Code Scanning compatible)
- False-positive suppression — allowlist patterns, ignore paths, baseline file
- Git hook — auto-generates a
pre-commithook that blocks commits on findings - Secret masking — secrets are never printed or stored in full (prefix/suffix only)
Installation
From PyPI
pip install secretleak
From source (development)
git clone https://github.com/your-org/secretleak.git
cd secretleak
pip install -e ".[dev]"
Using secretleak in Another Project
Option 1 — Install globally and scan manually
Install once, then point it at any repo:
pip install secretleak
secretleak scan /path/to/your-project
Option 2 — Add as a dev dependency
In your project's pyproject.toml:
[project.optional-dependencies]
dev = [
"secretleak",
]
Then install and scan:
pip install -e ".[dev]"
secretleak scan .
Or reference a local checkout before it is published to PyPI:
dev = [
"secretleak @ file:///path/to/secretleak",
]
Option 3 — Pre-commit hook (recommended for teams)
Run once inside the target repo. Every developer on the team is protected automatically — no changes to their workflow required.
cd /path/to/your-project
secretleak install-hook .
From that point on, every git commit scans the staged files and blocks if secrets are found:
[secretleak] Scanning staged files for secrets...
🔴 CRITICAL AWS Access Key ID — config.py:12 — AKIA****MPLE
[secretleak] !! Commit BLOCKED: secrets detected in staged files.
Remove the hook at any time:
secretleak uninstall-hook .
Option 4 — GitHub Actions (CI/CD)
Create .github/workflows/secret-scan.yml in your project:
name: Secret Scan
on: [push, pull_request]
jobs:
scan:
runs-on: ubuntu-latest
permissions:
security-events: write
steps:
- uses: actions/checkout@v4
- name: Scan for secrets
run: |
pip install secretleak
secretleak scan . --format sarif --output results.sarif --no-fail
- name: Upload to GitHub Code Scanning
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: results.sarif
Findings appear in your repo's Security → Code Scanning tab with file locations and line numbers.
Option 5 — Suppress false positives in your project
cd /path/to/your-project
# 1. Generate a baseline to silence already-known findings
secretleak generate-baseline .
git add .secretleak-baseline.json
git commit -m "chore: add secretleak baseline"
# 2. Add project-specific config
cat > .secretleak.yaml << 'EOF'
allowlist:
patterns:
- '^EXAMPLE_' # placeholder values in docs
- 'your-key-here' # obvious dummy values
paths:
- tests/fixtures/** # test data with fake secrets
- docs/**
baseline_file: .secretleak-baseline.json
EOF
Future scans will skip anything in the baseline and anything matching the allowlist.
Quick reference
| Goal | Command |
|---|---|
| Scan a project | secretleak scan /path/to/project |
| Scan staged files only | secretleak scan --staged |
| Scan a commit range | secretleak scan --commit-range HEAD~10..HEAD |
| Block commits automatically | secretleak install-hook . (run once) |
| CI pipeline (SARIF) | secretleak scan . --format sarif --no-fail |
| JSON report | secretleak scan . --format json -o report.json |
| Suppress known findings | secretleak generate-baseline . |
| List active rules | secretleak rules |
Quick Start
# Scan current directory
secretleak scan .
# Scan only staged files (before committing)
secretleak scan --staged
# Scan a commit range
secretleak scan --commit-range HEAD~10..HEAD
# JSON output
secretleak scan . --format json --output report.json
# SARIF output (GitHub Code Scanning)
secretleak scan . --format sarif --output results.sarif
# Install pre-commit hook
secretleak install-hook .
# Generate baseline to suppress existing findings
secretleak generate-baseline .
# List active rules
secretleak rules
Configuration
Create .secretleak.yaml in your repo root:
# Override entropy settings
entropy:
enabled: true
threshold: 4.5
min_length: 20
# Add custom rules
rules:
- id: my-internal-token
name: Internal Service Token
pattern: 'myapp_[a-z0-9]{32}'
severity: high
description: Internal service authentication token
# Allowlist – suppress known false positives
allowlist:
patterns:
- '^EXAMPLE' # example values in docs
- 'placeholder' # obvious placeholders
paths:
- tests/fixtures/** # test data
- '**/*.md' # documentation
# Additional paths to skip
ignore_paths:
- vendor/**
- node_modules/**
# Point at a baseline file
baseline_file: .secretleak-baseline.json
False Positive Handling
Allowlist patterns
allowlist:
patterns:
- '^fake_'
- 'example\.com'
Baseline suppression
Generate a baseline from the current state of your repo, commit it, and future scans will ignore already-known findings:
secretleak generate-baseline .
git add .secretleak-baseline.json
git commit -m "chore: add secretleak baseline"
Ignore paths
ignore_paths:
- docs/**
- tests/fixtures/**
- '**/*.lock'
CI Integration
# .github/workflows/secret-scan.yml
- name: Scan for secrets
run: |
pip install secretleak
secretleak scan . --format sarif --output results.sarif --no-fail
- name: Upload SARIF
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: results.sarif
Git Hook
# Install
secretleak install-hook .
# Force-overwrite an existing hook
secretleak install-hook . --force
# Uninstall
secretleak uninstall-hook .
The hook runs secretleak scan --staged and blocks the commit if any secrets are found.
Output Formats
Console (default)
Rich table with severity icons, file paths, line numbers, and masked secrets.
JSON
{
"version": "0.1.0",
"generated_at": "2026-03-09T12:00:00Z",
"scan_mode": "working_tree",
"summary": { "total": 2, "critical": 1, "high": 1 },
"findings": [
{
"fingerprint": "a3b4c5d6e7f8a1b2",
"rule_id": "aws-access-key-id",
"severity": "critical",
"file_path": "config.py",
"line_number": 12,
"secret_masked": "AKIA****MPLE",
...
}
]
}
SARIF 2.1.0
Compatible with GitHub Code Scanning. Upload via github/codeql-action/upload-sarif.
Exit Codes
| Code | Meaning |
|---|---|
0 |
No findings |
1 |
Findings detected (--no-fail to suppress) |
2 |
Error (bad args, git failure, config error) |
Development
# Install with dev dependencies
pip install -e ".[dev]"
# Run tests
pytest
# Run tests with coverage
pytest --cov=secretleak --cov-report=term-missing
# Lint
ruff check src/ tests/
ruff format src/ tests/
# Type check
mypy src/
Security Notes
- Secrets are never stored or logged in full. Only a masked form (
prefix****suffix) appears in output. - The JSON and SARIF outputs are safe to store and share — they contain only masked values.
- The baseline file contains only fingerprints (SHA-256 hashes), not secret values.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file secretleak-0.1.0.tar.gz.
File metadata
- Download URL: secretleak-0.1.0.tar.gz
- Upload date:
- Size: 26.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d9d10f0ecc50b5aedb9ae9c273f9f57aae7edc408fe20896668653a71fa55a72
|
|
| MD5 |
27bdba96ebc0580aea6b049df21da109
|
|
| BLAKE2b-256 |
21f05cb3d6aad587bff02830e7812ba9ebc9f4530417b654d997ee508f76aab8
|
Provenance
The following attestation bundles were made for secretleak-0.1.0.tar.gz:
Publisher:
publish.yml on Mo-Shakib/secretleak
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
secretleak-0.1.0.tar.gz -
Subject digest:
d9d10f0ecc50b5aedb9ae9c273f9f57aae7edc408fe20896668653a71fa55a72 - Sigstore transparency entry: 1060980107
- Sigstore integration time:
-
Permalink:
Mo-Shakib/secretleak@97ed7f1bd0b6ac653e2a2e85476a1fb5d46a63d2 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/Mo-Shakib
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@97ed7f1bd0b6ac653e2a2e85476a1fb5d46a63d2 -
Trigger Event:
release
-
Statement type:
File details
Details for the file secretleak-0.1.0-py3-none-any.whl.
File metadata
- Download URL: secretleak-0.1.0-py3-none-any.whl
- Upload date:
- Size: 24.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
28cd29e343474eb4c2962659a74174c0906bbf3bedb4f33526fea45ec7832d41
|
|
| MD5 |
661b03692c03133b17fc37cdd7883a92
|
|
| BLAKE2b-256 |
f1d112b46b93edc8805386d6f3dc5a52f52e91a0aab285671a957e687c8fb23a
|
Provenance
The following attestation bundles were made for secretleak-0.1.0-py3-none-any.whl:
Publisher:
publish.yml on Mo-Shakib/secretleak
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
secretleak-0.1.0-py3-none-any.whl -
Subject digest:
28cd29e343474eb4c2962659a74174c0906bbf3bedb4f33526fea45ec7832d41 - Sigstore transparency entry: 1060980235
- Sigstore integration time:
-
Permalink:
Mo-Shakib/secretleak@97ed7f1bd0b6ac653e2a2e85476a1fb5d46a63d2 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/Mo-Shakib
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@97ed7f1bd0b6ac653e2a2e85476a1fb5d46a63d2 -
Trigger Event:
release
-
Statement type: