Dev.to Security πŸ” Cybersecurity πŸ‘ 0 πŸ“– 3 min read

I built a local secret scanner

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 b

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.

πŸ“° Read the original article on Dev.to Security

Originally published by Dev.to Security. Aggregated on AIWithGhost for educational purposes β€” full credit and traffic to the original publisher.