0.0
The project is in a healthy, maintained state
SecretSweep scans a codebase (and optionally its full git history) for leaked secrets — API keys, tokens, private keys — using a combination of known-format regex patterns and Shannon entropy analysis for unknown formats. Pure Ruby standard library, zero runtime dependencies.
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
 Dependencies

Development

~> 13.0
~> 3.0
~> 3.13
~> 1.60
 Project Readme

SecretSweep

A dependency-free Ruby CLI that scans files and full git history for leaked secrets — API keys, tokens, private keys — using known-format patterns plus entropy analysis for everything else.

CI Gem Version Ruby Dependencies License

Why this exists

Secrets leak into git repos constantly — a hardcoded API key committed "just for testing," a .env file that wasn't gitignored in time. The sneaky part: removing the secret in the next commit does not remove it from git history. Anyone with git log -p can still read it. This tool scans both the working tree and full history, and treats them as equally important.

How it works

Two independent detection layers, deliberately kept separate:

  1. Pattern matching (PatternRegistry) — known formats: AWS keys, GitHub/Slack/Stripe tokens, PEM private key headers, JWTs, and a generic key = "..." assignment heuristic.
  2. Entropy analysis (Entropy) — Shannon entropy per character. Catches secrets in formats with no dedicated pattern yet (a new provider, an internal auth token) by flagging strings that are "suspiciously random" rather than matching a specific shape.

Both layers can flag the same secret independently — see Known limitations below for why that's left as-is rather than "fixed."

Installation

SecretSweep is published on RubyGems:

gem install secretsweep

Or from source:

git clone https://github.com/Majd2404/SecretSweep.git
cd SecretSweep
bundle install
gem build secretsweep.gemspec
gem install ./secretsweep-*.gem

Usage

# Scan the current directory's working tree
secretsweep .

# Also scan full git history (every branch)
secretsweep . --history

# Machine-readable output, e.g. for CI
secretsweep . --format json

# Use a specific ignore file
secretsweep . --ignore-file .secretsweepignore

Exit codes: 0 = clean, 1 = secrets found, 2 = error (e.g. not a git repo when --history was requested).

Example output

$ secretsweep . --history
Found 1 potential secret(s):

  [aws_access_key_id] config.rb @ 010f580376fd
    AKIA...MPLE  (fingerprint: 039a924b0920)

To allowlist a confirmed false positive, add its fingerprint to .secretsweepignore

That example is real — it's what secretsweep reports against a test repo where an AWS key was committed and then "removed" in a later commit. The removal didn't help; the key is still readable in history.

Ignoring false positives

Copy .secretsweepignore.example to .secretsweepignore in the directory you're scanning. Two kinds of entries:

# Skip scanning these paths entirely
spec/fixtures/**

# Allowlist ONE specific confirmed false positive by its fingerprint
# (does NOT silence the whole rule — just that exact file+type+snippet)
a1b2c3d4e5f6

Design decisions worth reading

  • Two detection layers, kept intentionally separate. Pattern matching and entropy analysis never share code — a bug in one can't silently break the other, and each is independently testable.
  • Fingerprints, not line numbers, are the identity of a finding. A fingerprint is a hash of source:type:snippet — it survives the file being edited above the secret, so an ignore-list entry doesn't silently stop working the next time someone touches that file.
  • The ignore list has two granularities on purpose. A path glob silences a whole directory (fixtures, generated files); a fingerprint silences exactly one confirmed false positive. Collapsing these into one mechanism would force a choice between "too broad" and "too narrow" for different real situations.
  • Git history scanning shells out to the real git binary rather than reimplementing pack-file parsing or depending on a native extension gem — git log -p --all is well-tested, always available wherever git itself is, and the output format is stable.
  • Zero runtime dependencies. The whole tool is Ruby stdlib (optparse, json, open3, digest, pathname, find). Anyone can gem install it with no dependency resolution at all.

Known limitations

  • The same secret can be reported twice, once by pattern matching and once by entropy analysis, if it happens to satisfy both (e.g. a GitHub token is both a recognized format and high-entropy). This is left as-is rather than deduplicated across types: two independent detectors agreeing is a legitimate confidence signal, and collapsing it would hide which detector(s) actually fired.
  • Entropy thresholds are heuristic, not yet validated against a large real-world sample.
  • History scanning reads the full diff of every commit on every branch (git log -p --all) — this is thorough but can be slow on very large, long-lived repositories. No pagination/depth limit yet.

Testing

bundle exec rspec

37 RSpec examples, including a real end-to-end test (git_history_scanner_spec.rb) that creates an actual throwaway git repo, commits a secret, removes it in a later commit, and verifies --history still catches it.

Type signatures are validated separately:

bundle exec rbs -I sig validate

Both run automatically on every push via GitHub Actions across Ruby 3.0–3.3 — see the CI badge above.

Tech stack

Ruby 3.0+, standard library only. RSpec for testing, RBS for type signatures, Rubocop for style, GitHub Actions for CI.

License

MIT — see LICENSE.