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.0.tar.gz (25.5 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.0-py3-none-any.whl (27.9 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: scrufflehog-0.1.0.tar.gz
  • Upload date:
  • Size: 25.5 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.0.tar.gz
Algorithm Hash digest
SHA256 cd98289e35bd12ca97051a2c45c1714154ce0f32503922054584d498675c4bb1
MD5 ea6ed79d9df38ecb91f1826f22e90248
BLAKE2b-256 5f59c64bd5dbadfdc9f613fca2362d97e293aaf61030591005fbbfd6116ac6f6

See more details on using hashes here.

Provenance

The following attestation bundles were made for scrufflehog-0.1.0.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.0-py3-none-any.whl.

File metadata

  • Download URL: scrufflehog-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 27.9 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.0-py3-none-any.whl
Algorithm Hash digest
SHA256 844d087aba979c484c76dd1eeaf5d4061e52cfb1ff1dc1aefcd763ce1af5b519
MD5 afde74b9f3b50567eadb7aceca8cd653
BLAKE2b-256 95a7fbadc131a3f0faae9a49453f1f2ec12e196769cf0240d65dbd0921e9b0d5

See more details on using hashes here.

Provenance

The following attestation bundles were made for scrufflehog-0.1.0-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