Project

leakferret

0.0
The project is in a healthy, maintained state
Context-aware secret scanning for Ruby projects. A thin wrapper around the native leakferret binary (written in Rust): it finds hardcoded secrets, confirms which ones are actually live by calling the provider, and rewrites them to read from environment variables instead. Precompiled platform gems bundle the native binary inside the gem, so a normal `gem install` ships the binary through RubyGems itself: no download, no network access, and no Rust toolchain. You can audit exactly what you are about to run with `gem unpack leakferret`. The gem never fetches and runs a binary off the internet - there is no download code to vet. On a platform without a prebuilt gem, the source gem tells you to build from source (`cargo install leakferret-cli`) or point LEAKFERRET_BIN at a binary. The API exposes Leakferret.scan, Leakferret.verify, and Leakferret.rewrite (each returning Finding objects), plus a `leakferret` command-line tool.
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
 Dependencies
 Project Readme

leakferret

leakferret (Ruby gem)

MCP-native secret scanner — verified findings, agent-applied rewrites.

Gem Version MIT MCP Badge

leakferret finds, verifies, and rewrites a leaked secret

Ruby gem wrapper around the native leakferret binary. This gem ships no scanning logic of its own: it installs a tiny Ruby shim plus the prebuilt, statically-linked engine (written in Rust). All the work — scan, classify, verify, rewrite — happens in that single binary.

You get a precompiled platform gem with the binary bundled inside it, the same way nokogiri and sorbet-static ship their native code, for x86_64 Linux (glibc), macOS (x86_64 and arm64), and x86_64 Windows. The binary travels through RubyGems with the gem — no download, no network access, no Rust toolchain — and you can audit exactly what you will run with gem unpack leakferret. The gem has no fetch-and-run code at all. On any other platform the source gem installs and points you at a one-line fix (build from source, or set LEAKFERRET_BIN); it never downloads a binary.

What leakferret does

leakferret finds hardcoded secrets and API keys in your code and helps you remove them, in five stations:

  1. Scan — regex pre-filter over files; respects .gitignore and also reads dotfiles like .env.
  2. Catalog — a signed database of known-public example credentials (Stripe test keys, AKIAIOSFODNN7EXAMPLE, jwt.io samples) so documented examples are marked FIXTURE instead of false-alarming.
  3. Classify — a REAL / FIXTURE / UNKNOWN verdict, from offline heuristics or by asking the host editor/agent language model (no extra API key, no cost).
  4. Verify — a real but harmless API call to the provider (AWS SigV4, GitHub, GitLab, Stripe, OpenAI, Anthropic, Slack, Twilio, SendGrid, Mailgun, Datadog, Heroku, npm, PyPI, DigitalOcean) to confirm a key is live, plus a trufflehog fallback.
  5. Rewrite — swap a hardcoded literal for an environment-variable lookup (ENV.fetch in Ruby, process.env in JS, os.environ in Python), add a .env.example line, and print secret-manager seed commands.

Privacy invariant: the full secret value never leaves your machine. Only a redacted first-4-plus-last-4 preview (e.g. AKIA...4XYZ) is ever written to a report, log, network message, or model prompt. Verification calls go straight from your machine to the provider — leakferret has no servers.

Install

gem install leakferret

RubyGems and Bundler select the right precompiled gem for your platform automatically, so the binary is already there after gem install — no first-run download. Inspect it before you trust it:

gem unpack leakferret        # the bundled binary is at lib/leakferret/bin/

Released gems carry GitHub build provenance (SLSA), so you can verify each gem was built from the tagged source in CI. On a platform without a prebuilt binary (e.g. aarch64-linux or Alpine/musl), the source gem still installs — so bundle install resolves — and tells you to build from source (cargo install leakferret-cli) or set LEAKFERRET_BIN. It never downloads.

Add it to a Gemfile for project-local use:

gem 'leakferret'

Requires Ruby >= 3.1.

CLI

The gem installs a leakferret executable that simply execs the binary, so every subcommand and flag works exactly as upstream:

leakferret scan .
leakferret verify . --only-verified
leakferret rewrite . --apply --backend doppler
leakferret baseline init
leakferret catalog info
leakferret mcp                 # MCP server on stdio

leakferret scan --git walks commit history. Output formats are pretty (colored terminal), json, and sarif (for GitHub Code Scanning).

Ruby API

require 'leakferret'

# Regex pre-filter only.
findings = Leakferret.scan('.')

# + provider-verified (live HTTP to GitHub / Stripe / AWS / ...).
findings = Leakferret.verify('.', mode: 'only-verified')

# + propose rewrites for REAL findings.
findings = Leakferret.rewrite('.', backend: 'doppler')

# Apply rewrites in place.
Leakferret.rewrite('.', apply: true)

Each Finding is a hash with path, line, column, pattern, severity (critical/high/medium/low), verdict (real/fixture/unknown), match_redacted, confidence, verification, and fingerprint.

Rewrite a leak

rewrite turns a hardcoded secret into an env-var lookup and helps you move it into a secret manager:

leakferret rewrite . --dry-run-diff               # preview the change, touch nothing
leakferret rewrite . --apply                      # write `ENV.fetch("KEY")` in place + add to .env.example
leakferret rewrite . --apply --backend doppler    # also print seed commands for your manager

--backend accepts env (default), vault, doppler, aws-secrets-manager, infisical. By default it only rewrites findings confirmed REAL/live; add --include-unknown to also fix unconfirmed candidates.

Use it in CI

leakferret is one binary with clear exit codes (0 = clean, 1 = findings), so it drops into any CI. The recommended pattern: baseline once, then verify on every build so you only fail on new secrets.

# One-time, on a repo that may already have findings:
leakferret baseline init            # fingerprints current findings (HMAC, never the raw secret)
git add .leakferret-baseline.json   # commit it — the per-repo salt is auto-gitignored

After that, verify ignores anything in the baseline and fails only on new leaks.

GitHub Actions — use the dedicated action (uploads SARIF to Code Scanning):

- uses: leakferrethq/leakferret-action@v1
  with: { path: ., fail-on: any }

CircleCI:

jobs:
  secrets:
    docker: [{ image: cimg/ruby:3.3 }]
    steps:
      - checkout
      - run: gem install leakferret
      - run: leakferret verify . --format sarif > leakferret.sarif
      - store_artifacts: { path: leakferret.sarif }

GitLab CI / Argo Workflows / Jenkins / anything else — identical recipe:

gem install leakferret
leakferret verify .                 # exits 1 on any REAL finding -> fails the job

Useful flags: --only-verified (fail only on provider-confirmed live keys), --verify-mode ever-verified (with a baseline, fail on anything that ever verified live), --format sarif|json.

Use it with AI agents (MCP)

leakferret is also an MCP server, so a coding agent (Cursor, Claude, Continue) can scan, verify, and rewrite before it commits. Add it to your editor's MCP config:

{
  "mcpServers": {
    "leakferret": { "command": "leakferret", "args": ["mcp"] }
  }
}

In Cursor: Settings → MCP → Add. In Claude Desktop: the mcpServers block of claude_desktop_config.json. Tools exposed: scan_repository, classify_candidates, verify_finding, propose_rewrite, baseline_diff.

Running leakferret mcp directly in a terminal looks like it hangs — that's correct. It's a stdio JSON-RPC server waiting for your editor to connect, not a command you run by hand.

Using a local binary

Every leakferret wrapper honors the LEAKFERRET_BIN environment variable. Point it at a binary on disk and the wrapper runs that instead of the downloaded copy:

export LEAKFERRET_BIN=/opt/leakferret/leakferret
leakferret scan .

For air-gapped or offline installs, set LEAKFERRET_SKIP_DOWNLOAD=1 to skip the release download and position the binary yourself.

Block commits locally (pre-commit hook)

Catch a secret before it is ever committed. From your repo root:

cat > .git/hooks/pre-commit <<'HOOK'
#!/bin/sh
# Offline secret scan (no network). Blocks the commit on any finding.
leakferret verify . --verify-mode none --fail-on any || {
  echo "leakferret blocked this commit. Bypass: git commit --no-verify"
  exit 1
}
HOOK
chmod +x .git/hooks/pre-commit

--verify-mode none keeps it offline; --fail-on any exits non-zero on any non-fixture finding (documented examples like AKIAIOSFODNN7EXAMPLE are still ignored). Pair with leakferret baseline init to block only on new secrets, or commit the hook to .githooks/ and run git config core.hooksPath .githooks to share it with a team.

License

MIT for this gem and the bundled binary. The fixture catalog data is CC-BY-SA-4.0 — see leakferret-catalog.


Part of leakferret · leakferret.com · maintained by Maria Khan <missusk@protonmail.com>.