v0.3.0Rustywoof v0.3.0 is out — local OSV lockfile auditing and browser WASM secret scanning.Read the release notes
Documentation
Concepts

Secret Scanning

How Rustywoof combines Aho-Corasick prefix matching, linear-time regex validation, and Shannon entropy to find leaked credentials.

Rustywoof detects hardcoded API keys, cloud credentials, and private tokens in your source files. To scan tens of thousands of files in a couple of seconds, it avoids running dozens of regular expressions over every line of code.

Instead, the scanner narrows down candidates step by step—starting with the fastest check and only running heavier checks when needed.

Fast Prefix Matching with Aho-Corasick

Most service providers design their API keys with a recognizable starting prefix:

  • AWS Access Keys start with AKIA
  • GitHub Personal Access Tokens start with ghp_, gho_, or ghs_
  • Stripe Live Keys start with sk_live_
  • Google Cloud Keys start with AIza

When Rustywoof starts up, it compiles all known prefixes into a single lookup table called an Aho-Corasick Deterministic Finite Automaton (DFA).

  • Single-pass reading: Rustywoof maps each file from disk into memory and reads through the bytes once.
  • Time complexity: $O(n + m + z)$, where $n$ is the file length, $m$ is the total length of the prefixes, and $z$ is the number of prefix hits.
  • Why this matters in practice: If a file does not contain any known prefix, Rustywoof finishes checking that file for prefixed tokens in microseconds without running a single regular expression.

Linear-Time Regex Verification

Finding ghp_ in a file doesn't automatically mean there is a real GitHub token—it could just be a comment or variable name.

Whenever the prefix matcher spots a hit, Rustywoof slices out the surrounding characters and validates them against that rule's regular expression to check the token's exact length and character set (such as Base62 or hexadecimal).

Because Rustywoof uses Rust's finite-automaton regex crate, pattern matching is guaranteed to run in linear $O(n)$ time. It cannot get stuck in catastrophic backtracking (ReDoS), even on minified JavaScript bundles or huge single-line JSON files.

Checking Randomness with Shannon Entropy

Not every secret has a neat prefix. Randomly generated JWT secrets, webhook signing keys, or database passwords often look like plain strings assigned to a variable:

const WEBHOOK_SECRET = "9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08";

To catch these—and to filter out obvious placeholder strings like AKIA_THIS_IS_A_TEST_KEY—Rustywoof calculates Shannon entropy, which measures how unpredictable the characters in a string are (in bits per character):

  • Ordinary English words or repeated characters ("aaaaaaaaaaaaaaaa") have low entropy (typically between $1.5$ and $3.5$).
  • Randomly generated hex or Base64 keys have high character variety and typically score above $4.5$.
  • If a string inside an assignment exceeds the entropy_threshold configured in your .woof.toml (default 4.5), Rustywoof flags it.

Dealing with false alarms: Occasionally, a harmless string like an integrity hash, an SVG path, or a mock test key will have high entropy. You can add those specific strings or test files to the [scanner.suppressions] list in .woof.toml so Rustywoof ignores them on future runs.

How is this guide?

Last updated on 09/11/2026