Skip to main content

Deterministically verify that your redactors actually redact.

Project description

scrufflehog

Unit-test your redaction.

Everyone scans for secrets that already leaked (trufflehog, gitleaks). Almost nobody tests whether the redaction they rely on actually works. scrufflehog is the inverse tool: it runs adversarial probes through your own redaction code and deterministically asserts the secret is gone — and checks that your field denylist/allow-list covers the sensitive names you think it does.

No model, no guessing: every verdict is a hard assertion against a planted secret you control. Zero false positives by construction.

Two things it checks

1. Transform-strengthdoes the redactor's output still contain, or trivially reverse to, the secret? It executes your redactor on planted probes and applies three oracles:

  • literal_survival — the secret appears verbatim in the output.
  • noop_passthrough — the "redactor" returned its input unchanged.
  • reversible — the output is a keyless, low-entropy transform (truncated or unsalted hash, base64, static substitution) that a bounded candidate space recovers. Catches "redaction" that only looks redacted.

2. Coverageis every sensitive field name actually on your list? A field denylist/allow-list is data, not behaviour, so scrufflehog extracts it straight from source and checks a sensitive-field corpus against it — without executing your code. This works across languages (Go maps, Python collections, pino/fast-redact path lists, Rust sets).

Languages

transform-strength coverage
Python in-process import
Go driver built in your module ✓ (map literals)
Rust cargo --example driver ✓ (set literals)
Node/JS node driver via stdin ✓ (pino path lists)

Install

Latest from source (works today):

pip install git+https://github.com/seanturner83/scrufflehog

Once the first release is published, from PyPI:

pip install scrufflehog

Use

Write a scrufflehog.toml declaring your redactors (see examples/):

[[transform]]
lang = "python"
module = "app/redact.py"
fn = "redact_value"
kind = "value"

[[coverage]]
module = "app/redact.py"
symbol = "SECRET_FIELDS"
extract = "py_collection"
match = "exact_ci"

Then:

scrufflehog verify --config scrufflehog.toml --target . --format text
scrufflehog verify --config scrufflehog.toml --target . --format sarif   # for code-scanning
scrufflehog verify --config scrufflehog.toml --target . --fail-on-defect # CI gate

Deterministic by default; optional agentic assist

The core is entirely deterministic and that's the point. An optional advisor (--advisor llm) can propose domain-matched probes, discover redactors, and confirm coverage hypotheses against real field usage — but it only ever supplies inputs and hypotheses; the deterministic oracle still renders every verdict. With no advisor, output is fully reproducible. See docs/AGENTIC.md.

Why "scrufflehog"

trufflehog finds the secrets. scrufflehog scruffs through the code that's supposed to hide them and checks it actually does.

License

MIT.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

scrufflehog-0.1.1.tar.gz (27.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

scrufflehog-0.1.1-py3-none-any.whl (28.6 kB view details)

Uploaded Python 3

File details

Details for the file scrufflehog-0.1.1.tar.gz.

File metadata

  • Download URL: scrufflehog-0.1.1.tar.gz
  • Upload date:
  • Size: 27.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for scrufflehog-0.1.1.tar.gz
Algorithm Hash digest
SHA256 497d6d3b6b73651f18bb797a6f7766b00b940894acd9131484bd0cbd3ffce2f0
MD5 b232d190046b239705833e084559afe8
BLAKE2b-256 cbb18a13893ab0e3e1cc939f258ee528a37de30e59cf193eeb04daaf51e4b4dc

See more details on using hashes here.

Provenance

The following attestation bundles were made for scrufflehog-0.1.1.tar.gz:

Publisher: release.yml on seanturner83/scrufflehog

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file scrufflehog-0.1.1-py3-none-any.whl.

File metadata

  • Download URL: scrufflehog-0.1.1-py3-none-any.whl
  • Upload date:
  • Size: 28.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for scrufflehog-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 a1a78693306cc1bedbce0db921f94acc3a3d70e2897e25726d8e1f668ebaa620
MD5 cc3d170ab1e199715262983eac355ea5
BLAKE2b-256 de36973a33d859cd320460f6e31e48ab9a8f38f15cf083caa9bcbfbc421ed87c

See more details on using hashes here.

Provenance

The following attestation bundles were made for scrufflehog-0.1.1-py3-none-any.whl:

Publisher: release.yml on seanturner83/scrufflehog

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page