Skip to content

Latest commit

 

History

History
131 lines (83 loc) · 14.5 KB

File metadata and controls

131 lines (83 loc) · 14.5 KB

Changelog

All notable changes to claude-guardrails are documented here. Format loosely follows Keep a Changelog.

[0.4.0] - 2026-06-05

Adds detection for two non-hex wallet private-key formats and hardens the BIP39 corpus. Until now the only crypto-key coverage was the 64-hex rule (which catches EVM keys incidentally) and the wordlist-based mnemonic scanner. Base58-encoded keys slipped through entirely. Both new rules lean on structured prefixes and fixed lengths, so they stay false-positive safe: xpub extended public keys, IPFS CIDs, P2PKH addresses, and non-5/K/L Base58 strings all pass clean.

Added

  • patterns/secrets.json - two rules: Bitcoin WIF private key (Base58, leading 5/K/L, 51-52 chars) and BIP-32 extended private key (xprv/yprv/zprv + testnet tprv/uprv/vprv, ~111 chars). Both apply everywhere the shared pattern set is used: prompts (scan-secrets.sh), commits (scan-commit.sh), and the personal-layer command/file checks.
  • New wallet-key-regex CI scenario (9 assertions) - WIF + xprv block; xpub, IPFS CIDv0, P2PKH address, and non-5KL Base58 pass. Vectors are built at runtime from a non-hex Base58 filler so no literal key lands in the source.
  • Seven bip39-scan CI cases - 24-word mnemonic and 4-per-line whitespace grid must block; two-sub-12 runs, a long-token break, and underscore-joined words must pass; the numbered-list mnemonic limitation is pinned as a documented pass; and a 10k-word ReDoS timing guard. CI: 11 scenarios / 105 assertions -> 12 scenarios / 121 assertions.

Notes

  • Numbered-list mnemonics (1. word 2. word ...) are a known, documented gap: digit+dot enumerators break the whitespace run. A future enumerator-stripping pass would close it but adds false-positive surface, so it is deferred.
  • Solana / raw Base58 keys are intentionally out of scope: no structural prefix means no false-positive-safe regex.

Upgrade note

Re-run bash install.sh <variant> (or npx claude-guardrails install) to pick up the new patterns/secrets.json.

[0.3.8] - 2026-04-17

Hotfix for v0.3.7. The wordlist-based BIP39 detector shipped in #9 replaced one false-positive regime with another: it tokenised prompts with scan("\b[a-z]{3,8}\b"), flattening punctuation out before counting runs, so any prose with 12+ BIP39 vocabulary words in a row got blocked. BIP39 wordlists include common English words (what, else, you, need, feel, that, ready, then, okay, ...), so a single user-reported sentence, "question. What else do you need? If you feel that's ready, then that's ready, okay.", tokenised to 13 wordlist hits and tripped the threshold.

Fixed

  • scan-secrets.sh (both variants) - the BIP39 pass now only flags runs of 12+ candidate tokens (3-8 lowercase letters) that are separated solely by whitespace, then confirms every token in the run is a wordlist member. Real mnemonics are space-separated in every wallet, so they still match; prose is broken up by punctuation, contractions, digits, or short words and no longer accumulates a run. Verified against the exact prompt the user reported: it now passes. Reported by @nntruonghan (#10).

Added

  • Two bip39-scan CI cases - 12 wordlist words joined by ", " must pass (was the failing case), newline-wrapped 12-word mnemonic must still block. CI: 11 scenarios / 103 assertions -> 11 scenarios / 105 assertions.

Upgrade note

Re-run bash install.sh <variant> (or npx claude-guardrails install) to pick up the new scan-secrets.sh. If you hit a BIP39 block on ordinary prose under v0.3.7, upgrading to v0.3.8 resolves it.

[0.3.7] - 2026-04-17

Replaces the BIP39 mnemonic detector. The previous pattern was (?i)(^|\s)([a-z]{3,8}\s+){11}[a-z]{3,8}(\s|$) — "12 or more consecutive lowercase words of 3-8 characters." Ordinary English prose hits that pattern routinely (30-plus short-word runs are common in natural writing), so scan-secrets.sh was blocking legitimate prompts. The regex was never a real BIP39 check; it was a short-word run detector with the wrong name.

Fixed

  • Wordlist-based BIP39 detection - scan-secrets.sh now loads the official 2048-word BIP39 English wordlist and blocks only when the prompt contains 12+ consecutive tokens all drawn from the list. BIP39 deliberately excludes common English stop-words ("the", "and", "for", "you", ...), so natural prose has near-zero probability of producing a false positive. Verified against the exact prose that previously tripped the regex: it now passes.
  • Removed the broken regex from patterns/secrets.json. The remaining rules (AWS, GitHub, Anthropic, OpenAI, Google, Slack, Stripe, 1Password, PEM, 64-hex, API_KEY=value) are unchanged. The labeled-secret rule already catches mnemonic: ... / seed_phrase: ... assignments, so labeled mnemonic leaks are still covered.
  • Scoping: the wordlist check runs in scan-secrets.sh (prompt scanner) only, not in scan-commit.sh. Running it on committed code hit too many false positives on legitimate content (documentation, test fixtures, the wordlist file itself). Commit-time leaks via labeled assignments are still caught by the labeled-secret regex.

Added

  • patterns/bip39-english.txt - the 2048-word list fetched from bitcoin/bips. Installed to ~/.claude/hooks/patterns/bip39-english.txt alongside secrets.json. Override path with $CLAUDE_GUARDRAILS_BIP39_WORDLIST for tests.
  • bip39-scan CI scenario - 7 assertions covering: prose with many short words allowed, real 12-word mnemonic blocked, 11-word near-miss allowed, missing wordlist fails open, AWS key still blocked alongside the BIP39 pass, plus install sanity on hook + wordlist files. Wired into the GitHub Actions matrix. CI: 10 scenarios / 96 assertions -> 11 scenarios / 103 assertions.

Upgrade note

Re-run bash install.sh <variant> (or npx claude-guardrails install) to pick up the new scan-secrets.sh, scan-commit.sh, and patterns/bip39-english.txt. The merge is additive and preserves custom deny rules and hooks. Until you re-run the installer, the old inline-regex scanner keeps producing false positives on ordinary prose.

[0.3.6] — 2026-04-17

Follow-up to v0.3.5. The previous release fixed the $schema bug for anyone re-running the installer (the jq merge always prefers the new file's value), but the fix happened silently — a user who ran v0.3.6 install after months on a broken v0.3.0–v0.3.4 install had no way to know their guardrails had been inactive the whole time. This release surfaces that state so users understand the remediation.

Added

  • Install-time remediation notice — when install.sh detects the pre-v0.3.5 $schema URL in an existing ~/.claude/settings.json, it prints a clearly-bordered NOTICE after the merge explaining (1) what the old value was, (2) that it silently disabled every guardrail in prior installs, (3) that it's been corrected, and (4) a pointer to the advisory in #6. Fresh installs and existing installs with the correct $schema stay quiet (no false positive).
  • schema-remediation CI scenario — 4 assertions covering: broken schema triggers the notice; post-install $schema is corrected; fresh install is quiet; correct-existing install is quiet. Wired into the GitHub Actions matrix. CI: 9 scenarios / 92 assertions → 10 scenarios / 96 assertions.

[0.3.5] — 2026-04-17

Critical hotfix. The wrong $schema URL shipped in every release from v0.3.0 through v0.3.4 caused Claude Code to silently discard the entire settings.json. Anyone who installed claude-guardrails fresh on a machine during that window got zero active guardrails — no deny rules, no hooks, no scanner. Reported and fixed by @valtumi in #3.

Fixed

  • $schema URL in both lite/settings.json and full/settings.json — was https://claude.ai/schemas/claude-code-settings.json (not accepted by Claude Code), now https://json.schemastore.org/claude-code-settings.json. Credit: @valtumi (#3).

Added

  • CI assertion on $schematest_lite_fresh, test_full_fresh, and test_merge_existing now verify the post-install $schema field matches the schemastore URL. This class of bug previously escaped CI because JSON-parseability and install/uninstall logic tests don't probe whether Claude Code actually honors the file. CI suite: 9 scenarios / 89 assertions → 9 scenarios / 92 assertions.

Upgrade note

If you have a pre-0.3.5 install, re-running npx claude-guardrails install merges the corrected $schema value into your existing ~/.claude/settings.json (the jq merge prefers the new file's value). Or manually edit the $schema field to https://json.schemastore.org/claude-code-settings.json. Until you do one of these, your guardrails are not active.

[0.3.4] — 2026-04-17

Adds a commit-time secret scanner, closing the gap between the prompt-submit scanner (which catches pasted credentials) and the code Claude writes and then tries to commit. Also tightens the direct-push guardrail's regex to kill a real-world false positive discovered while shipping this change.

Added

  • scan-commit.sh PreToolUse hook (both variants) — fires on Bash tool calls, inspects the command for git commit, runs git diff --cached --unified=0 through the same regex set as scan-secrets.sh, and blocks (exit 2) on match. Reports matched pattern name(s) and the list of staged files. Word-boundary matching avoids false positives on git commit-tree plumbing.
  • Shared pattern file patterns/secrets.json — single source of truth for credential regexes, loaded by both scan-secrets.sh (prompt) and scan-commit.sh (staged diff). Installs to ~/.claude/hooks/patterns/secrets.json. Closes v0.4 WS2 (pattern extraction).
  • New CI scenario scan-commit — functional test that stands up a throwaway git repo inside the sandboxed HOME and asserts seven response cases: clean diff allowed, AWS key blocked, git status passes through, git commit-tree plumbing not intercepted, git add && git commit chained form blocked, heredoc-wrapped commit message blocked, missing patterns file fails open.
  • New CI scenario push-hook — functional test for the direct-push-to-protected-branch guardrail. 13 cases: 7 block (direct, force, master, production, &&-chained, ;-chained, subshell-wrapped) and 6 allow (PR body with trigger phrase, echo commentary, grep searching for phrase, feature branch, main-prefixed branch name, non-push git command).

Changed

  • PreToolUse hook counts: lite 3 → 4, full 5 → 6.
  • Both scan-secrets.sh scripts refactored to load patterns from ../patterns/secrets.json (supports $CLAUDE_GUARDRAILS_PATTERNS override for testing). Behavior unchanged; pattern list and output format preserved.
  • Direct-push hook regex tightened to only match git push at a command-boundary position (start of string, or after &, |, ;, (). The old regex matched anywhere in the command string and false-positived on gh pr create --body "... git push origin main ..." — hit when creating this release's own PR. The trailing branch-name anchor also now requires whitespace / separator / EOS afterwards, so branches like main-feature-branch no longer trigger. Known regression: sudo git push origin main no longer matches — tradeoff documented.
  • CI suite: 7 scenarios / 58 assertions → 9 scenarios / 89 assertions, all green.
  • install.sh copies patterns/secrets.json + scan-commit.sh; uninstall.sh removes ~/.claude/hooks/scan-commit/ and ~/.claude/hooks/patterns/.

[0.3.3] — 2026-04-17

Alignment pass against Trail of Bits' claude-code-config threat model and deny-rule coverage.

Added

  • Privacy env flags in both variantsDISABLE_TELEMETRY=1, DISABLE_ERROR_REPORTING=1, CLAUDE_CODE_DISABLE_FEEDBACK_SURVEY=1. Intentionally does not set CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC because that flag also disables auto-updates.
  • Broader credential deny coverage — both variants add ~/.kube/** (cluster bearer tokens) and ~/.azure/** (Azure CLI creds). full adds six crypto-wallet app-support paths (MetaMask, Exodus, Phantom, Solflare, Electrum on macOS + ~/.electrum/** on Linux).
  • Redundant Bash deny rules as belt-and-suspenders alongside the PreToolUse hooks: Bash(sudo *), Bash(mkfs *), Bash(dd *), Bash(rm -rf *).

Changed

  • Deny rule counts: lite 15 → 21, full 28 → 40.
  • README "How It Works" restructured so /sandbox leads as the enforcement boundary and the other layers are framed explicitly as "can be bypassed." Adds a devcontainer pointer to Trail of Bits' companion repo for untrusted-code review sessions.
  • CI test get_deny_count() expectations updated across all 7 scenarios; still 58/58 assertions green.

[0.3.2] — 2026-04-17

Added

  • scan-secrets.sh UserPromptSubmit hook in both variants. Blocks prompts containing live credentials (AWS, GitHub, Anthropic, OpenAI, Google, Slack, Stripe, 1Password tokens; PEM private-key headers; BIP39 mnemonics; 64-hex private keys; API_KEY=value assignments). Prevents pasted secrets from reaching the model or being persisted to ~/.claude/projects/.../*.jsonl. Pure bash + jq — no new runtime dependency. ~11 ms median per invocation.
  • New docs/maintenance.md quarterly review checklist covering deny rules, PreToolUse hooks, the secret scanner, the prompt injection defender, and upstream threat research.
  • v0.4 "Maintainability & Sustainability" plan in docs/plan.md — pattern test corpus, data-file extraction, upstream tracking.

Fixed

  • tests/ci-test.sh now forces HOME to a fresh mktemp -d at script start and aborts if $HOME matches real-home patterns (/Users/*, /home/*, /root). Replaces the previous CI=true environment-variable gate on clean_claude_dir(), which was bypassable and led to the deletion of a real user's ~/.claude/ during development.

Changed

  • README, full/SETUP.md, lite/SETUP.md, and CLAUDE.md updated to document the new UserPromptSubmit layer and the 6-layer defense-in-depth model.
  • install.sh / uninstall.sh now handle UserPromptSubmit hooks in both variants (merge via jq on install, surgical removal on uninstall).
  • CI test suite grew from 7 scenarios / ~40 assertions to 7 scenarios / 58 assertions; all green.

Gitignore

  • .claude/settings.local.json (Claude Code writes machine-specific permission grants here during local sessions).

[0.3.0] — prior

Initial npm distribution. See git history (babf128 and earlier) for the install script, uninstall script, and lite/full variant baseline.