I keep finding API keys in repositories that were supposed to be private. Sometimes the key is in the current code. More often it is in a commit from months ago, deleted later, and still reachable through git log. So I built SecretSentinel: a small Python CLI that scans your working tree, your staged changes and your git history for hard-coded credentials.
Repository: github
Package: pypi
Install and run
pip install secretsentinel
secretsentinel scan # working tree (tracked and untracked, respecting .gitignore)
secretsentinel scan --staged # only lines you are about to commit
secretsentinel scan --history # every added line in the commit history
The exit code is 1 when something is found and 0 otherwise, so a CI job fails on a leak. Reports can be a console table, JSON, or SARIF 2.1.0 for GitHub code scanning:
secretsentinel scan --format sarif --output results.sarif
Why history matters
A secret deleted in the latest commit is not gone.
--history
checks every added line across all refs, and reports the commit where the secret appeared:
secrets.py:1:8 (commit 3f9a1c2b4d5e): [critical] aws-access-key-id: AKIA...VB (20 chars)
Rotating the key is still the real fix. The scan tells you where to look.
Design choices
- Local only. The scanner makes no network calls. It never checks whether a secret is still valid.
- No full secrets in output. Reports show a short preview and the length. JSON and SARIF hold a SHA-256 digest instead of the value.
- Rules are YAML. Each rule has an ID, a regex, a severity, a CWE, and an optional entropy threshold. The regex’s first capture group is the candidate secret, so entropy is measured on the secret and not on the text around it.
- Allowlist by digest. An accepted finding can be excluded by its SHA-256 digest, so the allowlist file never contains the secret.
- Ignore file. .secretsentinelignore skips paths, such as test fixtures.
A pre-commit hook is included, so the scan can block a commit before the secret reaches the repository:
repos:
- repo: local
hooks:
- id: secretsentinel
name: SecretSentinel
entry: secretsentinel scan --staged
language: system
pass_filenames: false
types: [text]
What it does not do yet
This is v0.1, and it is pre-alpha. Be aware of these limits:
- Detection is regex and entropy based. Expect false positives, and tune the rules and the allowlist for your project.
- Git history is loaded in memory. On very large repositories, use --max-commits.
- It does not validate keys against the provider. That is intentional, to keep the tool offline, but it means you still have to judge which findings are live.
- The built-in rules cover common providers: AWS, GitHub, Google, Slack, Stripe, private keys, and generic password and API key assignments. Your own patterns go in a rules file with --rules-file.
Other tools
Gitleaks (MIT, Go) and TruffleHog (AGPL-3.0, with verification of live secrets) are mature and widely used. SecretSentinel is a smaller Python tool. Its goal is to be easy to read and extend, with a simple YAML rule format and a small codebase. If you already use Gitleaks, keep using it.
Contributing
The project is Apache-2.0 licensed. Issues and pull requests are welcome. The CONTRIBUTING.md explains the layout and how to add a rule. To report a vulnerability in SecretSentinel, use the private reporting option described in SECURITY.md, not a public issue.
If you try it on a real repository and it finds something, or misses something, open an issue. That feedback is what the next version needs.
Top comments (0)