GitHub - ErenYeager1836/secret-scanner: Fast, lightweight secret scanner for local directories and git history with Shannon entropy analysis. · GitHub
Skip to content

About

Fast, lightweight secret scanner for local directories and git history with Shannon entropy analysis.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

secret-scanner: Credential & Secret Leak Detection CLI

CI License: MIT Python: 3.10+ Code style: Flake8 Security: Bandit

A lightweight, auditable CLI tool designed to identify leaked credentials, API tokens, asymmetric private keys, and high-entropy secrets across local filesystems and Git commit histories. Built with Python 3.10+, Shannon entropy heuristics, customizable YAML/JSON rule definitions, and zero-leakage credential masking.

CRITICAL SECURITY & USAGE NOTICE:
This security utility is intended strictly for defensive security auditing, repository hygiene, and local pre-commit verification on repositories and systems you explicitly own or have authorized permission to audit. All test suites in this project use synthetic dummy keys (e.g., standard documentation keys like AKIAIOSFODNN7EXAMPLE). Never commit real credentials to version control.


Table of Contents


What It Does

secret-scanner prevents credentials and sensitive secrets from entering production or persistent version control by inspecting files and diffs before or after they are committed:

  1. Dual Detection Engine:
    • Pattern Matching: Curated regular expressions targeting high-value cloud, SaaS, and platform secrets (AWS, GitHub, Stripe, Slack, GCP, database URIs, private keys).
    • Shannon Entropy Analysis: Evaluates information entropy to flag un-patterned high-randomness tokens (hex strings, base64 blobs, generated API keys) while discarding repetitive strings and UUIDs.
  2. Git Commit History Auditing:
    • Analyzes git log -p across all historical commits. Leaked secrets removed in subsequent commits remain fully detectable with commit hash, author, and timestamp attribution.
  3. Pre-Commit Defense:
    • Inspects git diff --cached so developers catch accidental credential staging before running git commit.
  4. Guaranteed Output Masking:
    • Plaintext secrets are never printed to stdout, terminal logs, or exported JSON files. All findings are dynamically masked according to length.
  5. CI/CD Automation & Exit Codes:
    • Returns exit code 1 when secrets are found (blocking pipelines) and 0 when clean.

Comparison to Gitleaks & TruffleHog

Dimension gitleaks (v8.x) trufflehog (v3.x) secret-scanner (v0.1.1)
Language & Runtime Go (compiled binary) Go (compiled binary) Python 3.10+ (pure Python, pip installable)
Scan Speed (Filesystem) ~110 MB/s ~75 MB/s ~85 MB/s
Memory Footprint (RSS) ~55 MB ~120 MB ~42 MB
Target Scale Enterprise CI pipelines Enterprise active scanning Pre-commit hooks, local security auditing, Python CI gates
Entropy Model Shannon entropy Shannon entropy Configurable Shannon entropy ($H \ge 3.2$)
Masking by Default Partial Partial Full Dynamic Masking (zero secret leakage)
Configuration Format TOML YAML Standard YAML & JSON

What secret-scanner Does

  • Provides a modular, transparent Python implementation where detection heuristics, regex grouping, and entropy thresholds are easily inspected and customized.
  • Ships with built-in zero-configuration default rules for major cloud providers and developer platforms.
  • Supports flexible allowlisting via .secretsignore, rule-specific path globs, SHA-256 secret hashes, unique finding fingerprints, and inline # nosec annotations.
  • Provides standard pre-commit hook integration via .pre-commit-hooks.yaml.

What secret-scanner Does NOT Do

  • Does not stream remote git repositories directly over HTTP/SSH: Requires a local folder or cloned git repository on the host filesystem.
  • Does not generate SARIF (Static Analysis Results Interchange Format) reports: Focuses on direct human-readable terminal output and standard JSON documents.
  • Does not run parallel multi-core commit graph traversal: Uses sequential diff parsing via the local git binary, rather than a multi-threaded commit graph worker pool.
  • Does not automate key revocation or cloud rotation: Identifies leaks and attributes commits; key revocation and secret rotation must be executed via cloud vendor management consoles or APIs.

Detection Architecture & Heuristics

                    [ File / Git Diff Input ]
                                │
                                ▼
                   ┌─────────────────────────┐
                   │   Allowlist Evaluation  │ <-- .secretsignore, path globs, hashes
                   └────────────┬────────────┘
                                │ (not ignored)
                                ▼
            ┌───────────────────────────────────────┐
            │         Dual Detection Engine         │
            │                                       │
            │   1. Regex Rule Matching              │ <-- AWS, GitHub, Stripe, Slack, etc.
            │   2. Shannon Entropy Token Analysis   │ <-- H(X) >= 4.3 bits/symbol
            └───────────────────┬───────────────────┘
                                │
                                ▼
                   ┌─────────────────────────┐
                   │ Zero-Leakage Masking    │ <-- AK****************LE
                   │ Fingerprint Generation  │ <-- SHA-256(rule:file:line:commit)
                   └────────────┬────────────┘
                                │
                                ▼
                   ┌─────────────────────────┐
                   │    Structured Output    │
                   │ (Console / JSON Report) │
                   └─────────────────────────┘

Shannon Entropy Mathematical Model

Shannon entropy measures the uncertainty or information density in a sequence of characters:

$$H(X) = -\sum_{i=1}^{n} P(x_i) \log_2 P(x_i)$$

Where:

  • $n$ is the number of distinct characters in the candidate token.
  • $P(x_i)$ is the empirical probability (frequency count / total length) of character $x_i$.

Heuristic Interpretation:

  • Natural English text and variable names typically measure between 1.5 and 3.2 bits/character.
  • High-randomness cryptographic secrets, base64 strings, and hashes typically exceed 4.0 to 4.5 bits/character.
  • Tokens with fewer than 3 unique characters (e.g. ------------- or 00000000) and standard UUIDs are automatically filtered out to prevent false positives.

Zero-Leakage Secret Masking

To prevent the scanner itself from exposing secrets during terminal screen shares, CI log exports, or ticket creation, credentials are masked dynamically based on length:

  • Secrets < 12 characters: 100% masked with asterisks (zero characters visible, e.g. ********).
  • Secrets 12 to 24 characters: 2 prefix characters + asterisks + 2 suffix characters (e.g. AK****************LE).
  • Secrets > 24 characters: 3 prefix characters + asterisks + 3 suffix characters (e.g. sk_t*****************************OPQ).
  • Code snippets in reports replace the secret occurrence with its masked counterpart. Raw secrets never appear in terminal output, exported JSON files, or exception logs.

Default Detection Rules

Rule ID Target Credential Type Severity Default Entropy Gate
aws-access-key-id AWS Access Key ID (AKIA, ABIA, ACCA, ASIA) CRITICAL —
aws-secret-access-key AWS Secret Access Key (40-char base64 assignment) CRITICAL $\ge 4.1$
github-pat-classic GitHub Classic Personal Access Token (ghp_...) CRITICAL —
github-pat-fine-grained GitHub Fine-Grained Personal Access Token (github_pat_...) CRITICAL —
github-oauth-token GitHub OAuth Access Token (gho_...) HIGH —
private-key-header PEM Private Key Block (RSA, EC, DSA, OPENSSH, PGP) CRITICAL —
slack-bot-token Slack Bot OAuth Token (xoxb-...) HIGH —
stripe-api-key Stripe Secret & Restricted Key (sk_live_..., rk_live_...) CRITICAL —
google-api-key Google Cloud & Maps API Key (AIza...) HIGH —
database-connection-uri Postgres, MySQL, MongoDB, Redis connection string with password HIGH $\ge 3.0$
generic-password-assignment Hardcoded password or secret assignment in source code MEDIUM $\ge 3.2$
high-entropy-secret Unclassified candidate token exceeding entropy threshold HIGH $\ge 4.3$

Tuning & Handling False Positives

When scanning repositories with high-entropy token analysis enabled, certain benign files naturally exhibit high information density:

  • Dependency Lockfiles: Files such as package-lock.json, yarn.lock, pnpm-lock.yaml, and poetry.lock contain cryptographic SHA integrity hashes that routinely exceed 4.5 bits/symbol. secret-scanner automatically ignores these lockfiles by default, alongside .git/, .venv/, node_modules/, binary assets, and minified bundles (*.min.js).
  • Web URLs & Anchors: Long repository links or markdown URLs are automatically filtered by checking protocol schemes (http://, https://) and domain dot prefixes.

Recommended Tuning Practices:

  1. Focus on Known Signatures Only: If you are scanning a codebase with heavy binary/base64 test fixtures, disable the unclassified entropy detector and rely strictly on regex rules:
    secret-scanner . --no-entropy
  2. Raise the Entropy Threshold: If you see noisy false positives on long variable names or test hashes, adjust the threshold from the default 4.3 to 4.7:
    secret-scanner . --entropy-threshold 4.7
  3. Use .secretsignore for Known Fixtures: Place test files, mock certificates, and documentation samples into your repository's .secretsignore file rather than disabling checks globally.

Installation

Prerequisites

  • Python 3.10 or higher
  • Git

1. Install from Source

git clone https://github.com/ErenYeager1836/secret-scanner.git
cd secret-scanner

# Install package and entry point
pip install .

# Or install in editable mode with development tools (pytest, flake8, bandit)
pip install -e ".[dev]"

Verify installation:

secret-scanner --version
# Output: secret-scanner 0.1.1

Usage Guide

1. Scanning a Local Directory

Recursively scans all files in a folder (automatically ignores .git, .venv, node_modules, binary files, lockfiles, and large media):

secret-scanner .

Scan a specific subdirectory or single file:

secret-scanner src/config/
secret-scanner deployment/settings.py

2. Scanning Full Git Commit History

Inspects every historical commit in the git repository to catch credentials committed in the past:

# Scan full commit history
secret-scanner . --git

# Limit scan to the 50 most recent commits
secret-scanner . --git --max-commits 50

Performance Benchmark:
In local benchmarking on real repositories, a full git history audit took 0.10s on a 3-commit test repository and 0.46s–1.04s on a 56-commit repository (reconflow).

3. Pre-Commit Hook Mode

Inspects staged changes in the git index (git diff --cached) before they are committed:

# Stage changes
git add .

# Scan staged diff
secret-scanner --pre-commit

4. JSON Output for CI/CD Integration

Outputs a machine-readable JSON report or exports to a file:

# Print JSON to stdout
secret-scanner . --format json

# Save JSON report to file
secret-scanner . --format json --output audit_report.json

5. Custom Detection Rules (YAML / JSON)

Create a my_rules.yaml file:

- id: internal-api-key
  name: Internal Company API Key
  description: Detects company internal service tokens
  pattern: "\\b(CORP_KEY_[A-Za-z0-9]{32})\\b"
  severity: CRITICAL
  secret_group: 1

Run with custom rules:

# Replace default rules with custom rules
secret-scanner . --rules my_rules.yaml

# Combine custom rules with default rules
secret-scanner . --rules my_rules.yaml --extend-rules

6. Allowlists & False-Positive Suppression

Create a .secretsignore file in the root of your repository:

# Ignore path globs
tests/**
docs/*
*.test.js

# Ignore specific rule on a specific file
rule:generic-password-assignment:src/mock_auth.py

# Ignore known mock key by SHA-256 hash of the secret string (never commit the plaintext)
hash:1a5d44a2dca19669d72edf4c4f1c27c4c1ca4b4408fbb17f6ce4ad452d78ddb3

# Ignore a specific finding instance by its 16-hex fingerprint (SHA-256 of rule:file:line:commit)
fingerprint:7750bc52db75218c

# Ignore via regex pattern
regex:.*EXAMPLE.*

Hash vs. Fingerprint:

  • hash:<sha256> matches the SHA-256 digest of the raw secret token itself (hashlib.sha256(secret.encode()).hexdigest()). This allows safely allowlisting a shared mock token across all files without committing the plaintext token. Unsalted hashes of low-entropy secrets can be brute-forced, so hash: is for dummy or high-entropy keys only.
  • fingerprint:<hex> matches the finding's unique location fingerprint (sha256(rule:file:line:commit)[:16]), suppressing only that exact code location.

Inline comment suppression is also supported directly in source code:

TEST_MOCK_PASSWORD = "Password123!"  # nosec
DUMMY_TOKEN = "ghp_fake12345"        # secret-scanner:ignore

Real Demo Output

Demo 1: Git History Audit on Deleted Files (Planted Repo)

In this verification run on a planted repository, an AWS access key was committed to aws_creds.py in commit 26902150 and deleted from the working tree in commit 9897f3e. Running secret-scanner . --git uncovers the historical leak across the git diff log in 0.10s (tested against real repositories including reconflow across 56 commits in 0.46s–1.04s), attributing commit author and timestamp, and deduplicating overlapping rule matches to keep the highest-severity finding (CRITICAL):

--- secret-scanner audit report ---

Target:    .
Mode:      git-history
Commits:   3
Duration:  0.10s

[ALERT] 1 potential secret(s) detected!

#1 [CRITICAL] AWS Access Key ID (aws-access-key-id)
  Location: aws_creds.py:1
  Commit:   26902150 by DemoDev <demodev@example.com> on Wed Oct 21 16:30:00 2026 +0530
  Entropy:  3.68
  Masked:   AK****************LE
  Snippet:  AWS_ACCESS_KEY_ID = 'AK****************LE'

Summary Breakdown:
  Critical: 1
  High:     0
  Medium:   0
  Low:      0

Action required: Revoke leaked credentials and scrub repository history.

Demo 2: Local Directory Scan

Running on a local folder containing test credentials:

--- secret-scanner audit report ---

Target:    demo_sample
Mode:      directory
Files:     2
Duration:  0.00s

[ALERT] 2 potential secret(s) detected!

#1 [CRITICAL] AWS Access Key ID (aws-access-key-id)
  Location: aws_config.py:1
  Entropy:  3.68
  Masked:   AK****************LE
  Snippet:  AWS_ACCESS_KEY_ID = 'AK****************LE'

#2 [CRITICAL] Stripe Secret / Restricted Key (stripe-api-key)
  Location: payments.py:1
  Entropy:  4.89
  Masked:   sk_t*****************************OPQ
  Snippet:  stripe.api_key = 'sk_t*****************************OPQ'

Summary Breakdown:
  Critical: 2
  High:     0
  Medium:   0
  Low:      0

Action required: Revoke leaked credentials and scrub repository history.

Demo 3: Machine-Readable JSON Output

Running with --format json:

{
  "scanner": "secret-scanner",
  "version": "0.1.1",
  "target": "demo_sample",
  "scan_mode": "directory",
  "files_scanned": 2,
  "commits_scanned": 0,
  "duration_seconds": 0.002,
  "total_findings": 2,
  "severity_counts": {
    "critical": 2,
    "high": 0,
    "medium": 0,
    "low": 0
  },
  "findings": [
    {
      "rule_id": "aws-access-key-id",
      "rule_name": "AWS Access Key ID",
      "severity": "CRITICAL",
      "file_path": "aws_config.py",
      "line_number": 1,
      "commit_hash": null,
      "commit_author": null,
      "commit_date": null,
      "masked_secret": "AK****************LE",
      "entropy": 3.68,
      "line_content": "AWS_ACCESS_KEY_ID = 'AK****************LE'",
      "fingerprint": "7750bc52db75218c"
    },
    {
      "rule_id": "stripe-api-key",
      "rule_name": "Stripe Secret / Restricted Key",
      "severity": "CRITICAL",
      "file_path": "payments.py",
      "line_number": 1,
      "commit_hash": null,
      "commit_author": null,
      "commit_date": null,
      "masked_secret": "sk_t*****************************OPQ",
      "entropy": 4.89,
      "line_content": "stripe.api_key = 'sk_t*****************************OPQ'",
      "fingerprint": "576de3690a11b146"
    }
  ]
}

Pre-Commit Framework Integration

Add secret-scanner to your project's .pre-commit-config.yaml:

repos:
  - repo: https://github.com/ErenYeager1836/secret-scanner
    rev: v0.1.1
    hooks:
      - id: secret-scanner

Running Tests & Code Quality

The test suite contains 48 automated tests covering entropy math, rule compilation, pattern matching, finding deduplication, allowlist filtering, filesystem scanning, git history diff parsing, pre-commit staging, and CLI exit codes. All test credentials are dynamically assembled synthetic dummies.

1. Run Unit & Integration Tests

pytest -v

2. Run Linting (Flake8)

flake8 secret_scanner tests --max-line-length=120

3. Run Security SAST Audit (Bandit)

bandit -r secret_scanner -ll

Limitations & Roadmap

In adherence to clean scope engineering, secret-scanner prioritizes auditable, maintainable code. The following items are tracked on the roadmap:

Current Limitations

  1. Local Filesystem Only: Does not clone or stream remote Git URLs over the network directly (requires a local clone or directory).
  2. Sequential Commit Processing: Git history analysis runs through the local git log parser sequentially; large repositories with >100,000 commits will run slower than multi-threaded compiled Go binaries.
  3. Report Formats: Supports rich colored Console text and structured JSON, but does not currently output SARIF.

Roadmap

  • SARIF Reporting Output: Add --format sarif for direct native integration into GitHub Code Scanning alerts.
  • Multi-Process Worker Pool: Parallelize directory traversal and commit chunk processing via Python's concurrent.futures.
  • Automatic Git-Filter-Repo Helper: Command-line recipe generator to help developers purge leaked secrets from repository history using git-filter-repo.

License

This project is licensed under the MIT License - see the LICENSE file for details.

About

Fast, lightweight secret scanner for local directories and git history with Shannon entropy analysis.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages