Documentation

leakferret is one Rust binary that is engine, CLI, and MCP server. It finds hardcoded secrets, confirms which are live, and rewrites them to read from an environment variable. Everything below reflects v0.1.4.

Install

Every package runs the same prebuilt binary. The Ruby gem bundles it inside precompiled platform gems, so gem install ships the binary through RubyGems with no download (audit it with gem unpack leakferret). The other wrappers download it from GitHub Releases on first use and verify it against a pinned SHA256.

# npm (CLI)
npm i -g @leakferret/cli

# Ruby gem
gem install leakferret

# Go
go install github.com/leakferrethq/leakferret-go/cmd/leakferret@latest

# Rust, from source
cargo install leakferret-cli

# Or grab a binary from the releases page and put it on $PATH
# https://github.com/leakferrethq/leakferret/releases
Every wrapper honors LEAKFERRET_BIN — point it at a local binary to use your own (offline or development use).

Quick start

# 1. Fast regex scan of the working tree
$ leakferret scan .

# 2. Scan + classify + verify which keys are actually live
$ leakferret verify .

# 3. See the env-var rewrite as a diff, without touching files
$ leakferret rewrite . --dry-run-diff

# 4. Apply the rewrites in place
$ leakferret rewrite . --apply

scan respects .gitignore and also reads dotfiles such as .env. Add --git to walk commit history instead of the working tree.

Block commits locally (pre-commit hook)

Stop 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 fully offline; --fail-on any exits non-zero on any non-fixture finding (documented examples like AKIAIOSFODNN7EXAMPLE are still ignored). Pair with leakferret baseline init so the hook only blocks on new secrets.

CLI reference

Global options apply to every command: -q/--quiet, -v/-vv/-vvv (verbosity), -h/--help, -V/--version.

leakferret scan [PATH]

Regex pre-filter only — no classifier, no verifier. Fastest mode.

FlagMeaning
--gitScan git history (HEAD's reachable commits) instead of the working tree.
--allWith --git: scan every branch and tag, not just HEAD — catches secrets on un-merged branches.
--since <REV> / --until <REV>History window for --git (e.g. HEAD~10, a tag, a SHA).
--max-depth <N>Cap on commits walked (safety valve for huge histories).
-f, --formatpretty (default), json, sarif.
--show-fixturesInclude FIXTURE-classified findings in output.
--exclude [<GLOB>…]Extra glob excludes, on top of .gitignore.
--only [<PATH>…]Limit to specific files (pre-commit-hook mode).
--only-verifiedEmit only findings the verifier confirms live (forces the verifier to run).
--fail-on <none|any|real|verified>Exit non-zero when findings at this level are present. any blocks on any non-fixture finding — use it with --verify-mode none for an offline pre-commit gate. Omitted keeps the historical exit codes.

leakferret verify [PATH]

Scan + offline-heuristic classify + provider verification. Inherits all scan flags, plus:

FlagMeaning
--verify-modenone, best-effort (default), only-verified, ever-verified.
--verifier-timeout-secs <N>Per-verifier timeout (default 10).
--update-baselineRecord the current findings into the baseline (writes the baseline / history / salt). Off by default — a plain verify never writes to your repo.

leakferret rewrite [PATH]

Scan + classify, then propose ENV-fetch rewrites for REAL findings. Inherits all scan flags, plus:

FlagMeaning
--applyApply rewrites in place (default is dry-run).
--dry-run-diffPrint the unified diff per file without writing.
--checkCI mode: like --dry-run-diff but exits 1 if any rewrites are pending.
--backendSeed-command target: env (default), vault, doppler, aws-secrets-manager, infisical.

leakferret baseline <init|show|ignore>

Manage .leakferret-baseline.json — one-way HMAC fingerprints of acknowledged findings, so CI fails only on new leaks. init creates it (and gitignores the secret salt), show prints it, ignore --fingerprint <fp> acknowledges a finding. scan/verify are read-only and never write these files — you record with verify --update-baseline.

leakferret catalog <info|list|test|refresh>

info prints catalog metadata; list dumps entries as JSON; test <value> prints the verdict for a value; refresh fetches a fresh catalog from the CDN and verifies its Ed25519 signature before persisting it.

leakferret mcp

Start the MCP server on stdio. See Editors & agents.

Output formats

FormatUse
prettyColored terminal output (default).
jsonStructured findings for scripting and pipelines.
sarifFor GitHub Code Scanning; the Action uploads it for you.

Allowlisting false positives

Suppress a single finding with an inline comment pragma, kept next to the value it concerns:

API_KEY = "AKIA…"  # leakferret:allow aws_access_key reason="tutorial fixture"

Editors & coding agents (MCP)

MCP (Model Context Protocol) lets a coding agent call leakferret's pipeline itself — so it self-checks before committing. The server exposes scan_repository, classify_candidates, verify_finding, propose_rewrite, and baseline_diff, plus a classify prompt.

The shared config block (works for Claude Desktop, Cursor, and Continue):

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

If you installed the native binary, point at it directly instead:

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

Claude Code

$ claude mcp add leakferret -- npx -y @leakferret/mcp

Then ask Claude to scan before it commits. Use claude mcp list to confirm it registered.

Cursor

Create .cursor/mcp.json in the project (or the global one) with the shared block above. Cursor shows the server under Settings → MCP.

Continue

Add the shared block to ~/.continue/config.json (the mcpServers key). Restart the IDE panel to load it.

Claude Desktop

Edit claude_desktop_config.json and add the shared block, then restart the app:

OSPath
macOS~/Library/Application Support/Claude/claude_desktop_config.json
Windows%APPDATA%\Claude\claude_desktop_config.json

VS Code extension

Install leakferret from the VS Code Marketplace (or Open VSX for VSCodium/Cursor). It bundles the binary and surfaces findings inline.

CI

GitHub Actions

# .github/workflows/secrets.yml
name: secrets
on: [push, pull_request]
jobs:
  scan:
    runs-on: ubuntu-latest
    permissions:
      security-events: write   # for SARIF upload
    steps:
      - uses: actions/checkout@v4
      - uses: leakferrethq/leakferret-action@v1
        with:
          verify-mode: only-verified
          fail-on: any

Inputs: version (default latest), path, verify-mode, format (default sarif), fail-on (low|medium|high|critical|any), baseline-path, upload-sarif, category, github-token. Outputs: findings-count, verified-count, sarif-path.

Any other CI

Install the binary and run a command — exit code 1 means action needed:

$ leakferret verify . --verify-mode only-verified --format json
$ leakferret rewrite . --check   # exits 1 if rewrites are pending

Baselines

A baseline records the findings you already know about, so CI fails only on new leaks. verify is read-only — it never writes to your repo — so you record a snapshot explicitly:

# one-time: create the baseline (gitignores the secret salt for you)
$ leakferret baseline init
# record current findings, then commit the baseline
$ leakferret verify . --update-baseline
$ leakferret baseline ignore --fingerprint <fp>   # acknowledge one finding

Commit .leakferret-baseline.json and .leakferret-history.jsonl; .leakferret-salt stays gitignored — it must remain secret. In CI, a plain leakferret verify . then fails on any finding not already in the baseline.

How it works

  1. Scan — regex pre-filter over files (respects .gitignore, reads dotfiles, optionally walks history).
  2. Catalog — candidates checked against a signed database of known-public examples; matches are marked FIXTURE.
  3. Classify — verdict per candidate: REAL, FIXTURE, or UNKNOWN. Runs offline by default.
  4. Verify — one harmless API call confirms a key is LIVE. The call goes straight to the provider.
  5. Rewrite — swaps the literal for an env-var lookup, appends to .env.example, prints secret-manager seed commands.

Verifiers

Around 25 providers are verified natively: AWS (SigV4), GitHub, GitLab, Stripe, OpenAI, Anthropic, Slack, Twilio, SendGrid, Mailgun, Datadog, Heroku, npm, PyPI, DigitalOcean, Hugging Face, Groq, Replicate, Notion, Postman, Figma, Linear, Square, Shopify, Databricks. leakferret detects 60+ secret types in all.

For providers without a native verifier, leakferret falls back to a trufflehog binary if it's on your PATH (or pointed at by LEAKFERRET_TRUFFLEHOG_BIN). Without it, those findings stay UNKNOWN rather than failing. trufflehog is an optional, user-installed AGPL-3.0 tool invoked as a separate process — not bundled, modified, or redistributed by leakferret.

Each verification is a single least-privilege call (e.g. AWS STS GetCallerIdentity). Set --verifier-timeout-secs to bound slow networks. --verify-mode ever-verified fails on keys that were ever live, even if revoked now.

Fixture catalog

A signed database of documented-public example credentials (Stripe test keys, AKIAIOSFODNN7EXAMPLE, jwt.io samples, RFC examples). It is bundled into the binary, so a fresh install already suppresses these. Refresh and signature-verify an update with leakferret catalog refresh; inspect with leakferret catalog info.

Privacy & security

The full secret value lives only on disk. It is never serialized, logged, or sent in any report, log, network message, or model prompt. Only a redacted first-4 + last-4 preview (e.g. AKIA…4XYZ) ever leaves the process — a dedicated test enforces this. Verification calls go straight from your machine to the provider; leakferret has no servers and collects nothing. Baselines store one-way HMAC fingerprints, never the raw secret.

Platforms & caveats

Prebuilt binaries for v0.1.0:

aarch64 Linux is not in v0.1.0 (it lands in v0.1.1). On that platform, install with cargo install leakferret-cli from source, or set LEAKFERRET_BIN.

Troubleshooting

SymptomFix
Install can't download the binarySet LEAKFERRET_BIN to a local binary, or install via cargo install leakferret-cli.
A documented example key is flaggedRun leakferret catalog refresh, or add a leakferret:allow pragma.
A key shows UNKNOWN instead of LIVENo native verifier for that provider and no trufflehog on PATH, or the verifier timed out.
CI doesn't fail on a known leakCheck --verify-mode / fail-on, and that the finding isn't in the baseline.

Source & issues on GitHub →