M126 Bundle C — secret-handler hook

Closes #1543. New PostToolUse hook scans Read/Bash/Grep/Glob output for API keys + private blocks via CC 2.1.121's updatedToolOutput. OFF by default — operators opt in via ORK_SECRET_HOOK env var.
CC 2.1.121 tests 55/55 patterns 6 bounded · 3 critical audit fixes 5 of 5 applied

Try it — paste tool output, watch the hook process it

ORK_SECRET_HOOK mode

tool_output (in) 0 chars

updatedToolOutput (out)

Pattern catalog (after audit fixes)

#PatternClassAction on hitAudit verdict
1github-patboundedin-place [REDACTED:github-pat]tightened — added github_pat_ FN
2anthropic-keyboundedin-placeship as-is
3openai-project-keyboundedin-placeNEW — sk-proj-* was silent FN
4openai-keyboundedin-placetightened — exact 48 chars
5aws-access-key-idboundedin-placeloosened — AKIA + ASIA + AROA + AIDA + …
6slack-tokenboundedin-placeextended — added xoxe/xoxs/xapp
7ssh-private-keycriticalGATE entire outputship as-is
8gpg-private-keycriticalGATEship as-is
9aws-secret-access-keycriticalGATE (with assignment context)tightened — case-insensitive

Why three modes

ModeDefaultBehaviorWhen to use
OFFHook returns early; zero overheadInitial rollout — preserve current behavior
AUDITWrites .claude/state/secret-audit.jsonl; output unchangedTune regex set against real traffic ~30d before flipping enforcement
REDACTBounded → in-place; critical → gate entire outputAfter AUDIT shows low FP rate

The AUDIT step matters: regex false positives are the failure mode operators feared most when shipping output mutation. AUDIT lets you observe FPs against real traffic before any model behavior changes.

Test strategy — inverted fixtures

Growing corpus of negative fixtures (must NOT match) is the regression guard. Adding a "this matched but shouldn't" case is one line in negative-corpus.ts. Today's negative corpus catches: UUIDs, git SHAs, npm sha512 integrity, JWTs without claims, bcrypt hashes, IPv6, isolated 40-char base64 (no AWS context), npm shrinkwrap, build artifacts.