home

docs

token-hunt v0.1.0

Python 3.10+ · zero cloud, zero telemetry · fail-closed ·source on GitHub

01 Install

$pip install token-hunt# standalone cli
$claude plugin install token-hunt@JordanNewell# the six-hook guard

The plugin is the only step most people need — it wires all six hooks into Claude Code. The pip package is the engine underneath and the standalone CLI; the plugin drives it. Cursor and Aider work today via the CLI peer (manual wiring); first-class plugin integrations ship in v0.2.

02 The six hooks

Every point a secret can enter the transcript has a hook on it. BLOCK hooks stop the tool call before it runs. WARN hooks can't un-ring the bell — the paste or output is already in the transcript — so they banner the agent and log the finding for rotation.

hookwhat it seesaction on leak
UserPromptSubmityour pasteWARN
PreToolUse:Bashcommand about to runBLOCK
PostToolUse:Bashcommand outputWARN + log
PostToolUse:Readfile contentsWARN + log
PreToolUse:Edit/Writenew file contentBLOCK
PostToolUse:Edit/WriteechoWARN + log

Fail-closed: if the scanner itself crashes inside a hook, the tool call isBLOCKED with a bypass hint — never silently allowed.

03 CLI

$ token-hunt scan <path>

Scan a file or directory. Findings print with rule, line, and a rotate URL.

  • --stdin — read text from stdin instead of a file
  • --context <point> — pretend to run at this hook (default UserPromptSubmit)
  • --format text|json — output format (default text)
  • --no-log — don't write the finding to rotations.log

$ token-hunt list

List open leaks from rotations.log, newest first.

  • --all — include closed leaks too

$ token-hunt close <id>

Mark a leak closed after you rotated the key. Overdue finds stay flagged past 72h.

  • --note <text> — rotation note, e.g. "rotated at console.anthropic.com"

$ token-hunt watch <dir>

Watch a directory live — e.g. your agent transcript dir — and scan every file change.

  • --context <point> — hook to attribute findings to (default PostToolUse:Read)
  • --exit-after <n> — exit after n seconds instead of running forever
$token-hunt watch ~/.claude/projects/
$token-hunt list
$token-hunt close 1 --note "rotated at console.anthropic.com"

04 Bash escape-hatch detection

Bash evaluates secrets into emitted text with no literal in sight — no regex scanner can see the value because it never appears. token-hunt ships a runtime detector for this class in the PreToolUse:Bash hook:

BLOCKED

echo ${ANTHROPIC_API_KEY:+SET}
${ANTHROPIC_API_KEY:-UNSET}

both branches run — the value leaks

BLOCKED

echo $GITHUB_TOKEN

direct echo of a secret var

ALLOWED

[ -n "$ANTHROPIC_API_KEY" ] \
  && echo SET

status check — no value emitted

A variable counts as secret-bearing when its name ends in _KEY,_TOKEN, _SECRET, _PASSWORD, _PAT and friends, or starts with a known provider prefix (ANTHROPIC_,OPENAI_, GITHUB_…). Non-secret vars echo freely.

05 Configuration

Pattern layers

Later layers extend earlier ones — your local rules add to the builtin 48, never replace them.

  1. 1builtin.toml — ships with the package — 48 rules
  2. 2~/.token-hunt/patterns.local.toml — machine-local, gitignored
  3. 3./.token-hunt/patterns.local.toml — repo-local, gitignored

Allowlist

Test fixtures and known fakes go in ~/.token-hunt/allowlist.toml by SHA-256 fingerprint (first 16 chars of the value), or path-based, so findings never re-fire:

fingerprints = [
  "a1b2c3d4e5f60718...",  # fake fixture, tests/
]

Environment

TOKEN_HUNT_DISABLE=1Per-repo opt-out. Disables every hook. For repos you trust and nothing else.
TOKEN_HUNT_ALLOW=1One-shot bypass of the BLOCK hooks only (Bash, Edit/Write). The WARN hooks always fire — they block nothing, so there is nothing to bypass. Use sparingly.

06 Rules & providers

48 rules cover 51 providers in three tiers:

Extend or override anything with a local pattern layer (§05). Every finding carries its rule id, so you always know which rule fired.

← tokenhunt.dev ·changelog ·issues