fix(guardrails): fail closed on over-length Bash before tokenize; linear parse (#4528) - #4699
Merged
Merged
Conversation
…and parse once, linearly (#4528) The Bash|PowerShell PreToolUse row ran past its 60-second hooks.json timeout on a long command, and Claude Code lets a timed-out PreToolUse command hook's tool call proceed, so the command passed every guard unchecked. On main: 7.23 s at 10 KB, 12.6 s at 16 KB, still running at 120 s for ~70 KB. Now 132 ms, 203 ms and 64 ms. - lib/hook-utils.sh: hook::bash_parse_segments split the command with one ${cmd:i:1} per character, which bash answers by measuring the whole string, so every parse was quadratic. It now splits in 4096- and 64-byte blocks under the C locale; output is byte-identical. The body moves to hook::bash_parse_segments_uncached behind a thin wrapper (the hook::jq_fields split). Synced to the 17 carriers, each patch-bumped. - run-guards.sh: --max-command-len <n> ends the chain at the first guard that blocks a command longer than <n>. The Bash row passes 16384, the MAX_COMMAND_LEN five of its guards already refuse unread; block-no-verify runs first. Kill switches are unchanged: a disabled guard exits before its ceiling and the next one blocks. - run-guards.sh: the event's command is tokenized once and the record is replayed to every later guard that parses it; a parse cut short by a guard's exit is not kept. Tests: run-guards.test.sh covers the short-circuit (stub and shipped row, kill switch, unprimed payload, boundary, bad value), the row/guard ceiling parity, and the shared parse (equality with a standalone parse, one walk, cut-short parse). lib/hook-utils.test.sh covers the byte walk, locale restore, and an 8x-size cost ratio (7x now, 45x on main). Co-authored-by: Kyle Sexton <kyle-sexton@users.noreply.github.com>
…rlength-fastpath-37e9 # Conflicts: # plugins/source-control/CHANGELOG.md Co-authored-by: Kyle Sexton <kyle-sexton@users.noreply.github.com>
validate-plugin-contracts forbids the autonomy plugin from naming the org or fleet repos. Co-authored-by: Kyle Sexton <kyle-sexton@users.noreply.github.com>
… command (#4528) The 0.37.3 entry said four guards with no ceiling each tokenized the whole command; flag-commit-pr-skill-bypass never calls the tokenizer and is off by default. A per-guard profile of main on a 70 KB command shows block-hook-bypass, block-noncanonical-commit and block-convention-violation at about 44 s each. Co-authored-by: Kyle Sexton <kyle-sexton@users.noreply.github.com>
…rlength-fastpath-37e9 Resolve the source-control 0.61.3 collision by keeping main's changelog entry and re-heading this branch's hook-utils change as 0.61.4. Co-authored-by: Kyle Sexton <kyle-sexton@users.noreply.github.com>
Contributor
|
PR body contract — issue linkage This PR body does not yet satisfy the issue-linkage contract:
Edit the body and this comment updates itself on the next run. |
1 task done
Co-authored-by: Kyle Sexton <kyle-sexton@users.noreply.github.com>
Shellcheck info SC2030/SC2031 flags LC_ALL assignments whose subshell is the point of the test, and the portability gate flags a grep -F fixture token. Co-authored-by: Kyle Sexton <kyle-sexton@users.noreply.github.com>
1 of 2 tasks
The DLSS selftest's user-only Set-Acl deny still lets an elevated runner list the folder, and Windows often leaves the error TargetObject empty, so the four unreadable-folder assertions never match. Co-authored-by: Kyle Sexton <kyle-sexton@users.noreply.github.com>
DirectoryInfo.SetAccessControl is absent in PowerShell 7, so the Windows selftest threw before the deny cases ran. Write the same user, Administrators, and Everyone list deny through FileSystemAclExtensions. Co-authored-by: Kyle Sexton <kyle-sexton@users.noreply.github.com>
A Deny ACE, including one for Everyone, still lets the elevated Windows runner list the folder. Hold the directory open with no sharing so the next Get-ChildItem fails with a sharing violation, and recover a quoted path from the error message when TargetObject is empty. Co-authored-by: Kyle Sexton <kyle-sexton@users.noreply.github.com>
The runner's pwsh has no FileOptions.BackupSemantics, so the selftest threw before the sharing lock was taken. Open the directory with CreateFileW and FILE_FLAG_BACKUP_SEMANTICS instead. Co-authored-by: Kyle Sexton <kyle-sexton@users.noreply.github.com>
1 task done
cursor Bot
pushed a commit
that referenced
this pull request
Sep 27, 2026
… act on (#4679) (#4711) <!-- CURSOR_AGENT_PR_BODY_BEGIN --> Closes #4679 **Stacked on #4699** (`cursor/4528-guard-overlength-fastpath-37e9`). Until that merges, the diff against `main` includes its commits; review the commits after `d6963e5c1`. ## Summary `block-hook-bypass` refusals drop operator lever spam and wrong scratch-root advice on PowerShell/python. stderr carries only actionable lines; levers go to one `systemMessage` per session/agent (latched via `HOOK_NOTICE_KIND == full`). README keeps the write-forms list. One-line README pointer remains until a human confirms exit-2 `systemMessage` renders. `guardrails` → 0.38.0 (stacked above 0.37.3 from #4699). ## Test plan - [x] block-hook-bypass 699/0 outside `/tmp` (per implementer) - [ ] Interactive: confirm `systemMessage` shows on exit-2 block <!-- CURSOR_AGENT_PR_BODY_END --> <div><a href="https://cursor.com/agents/bc-ab53da24-b89d-4314-a060-0da474e837e9?cursor_ref=pr_footer&cursor_cta=open_in_web"><picture><source media="(prefers-color-scheme: dark)" srcset="https://cursor.com/assets/images/open-in-web-dark.png"><source media="(prefers-color-scheme: light)" srcset="https://cursor.com/assets/images/open-in-web-light.png"><img alt="Open in Web" width="114" height="28" src="https://cursor.com/assets/images/open-in-web-dark.png"></picture></a> <a href="https://cursor.com/background-agent?bcId=bc-ab53da24-b89d-4314-a060-0da474e837e9&cursor_ref=pr_footer&cursor_cta=open_in_cursor"><picture><source media="(prefers-color-scheme: dark)" srcset="https://cursor.com/assets/images/open-in-cursor-dark.png"><source media="(prefers-color-scheme: light)" srcset="https://cursor.com/assets/images/open-in-cursor-light.png"><img alt="Open in Cursor" width="131" height="28" src="https://cursor.com/assets/images/open-in-cursor-dark.png"></picture></a> </div> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Kyle Sexton <kyle-sexton@users.noreply.github.com>
# Conflicts: # plugins/guardrails/.claude-plugin/plugin.json # plugins/guardrails/CHANGELOG.md Co-authored-by: Kyle Sexton <kyle-sexton@users.noreply.github.com>
cursor Bot
pushed a commit
that referenced
this pull request
Sep 28, 2026
…eck (#4680) (#4709) <!-- CURSOR_AGENT_PR_BODY_BEGIN --> Closes #4680 ## Summary `hardcoded-path-check` never scanned real `NotebookEdit` calls (reads `file_path`; Claude Code sends `notebook_path`). Mirrors #4486. Shared test helper now builds the real payload shape. `guardrails` → 0.37.3 (serialize vs #4699 / other guardrails bumps). ## Test plan - [x] hardcoded-path-check 153/0; new cases fail on main (per implementer) <!-- CURSOR_AGENT_PR_BODY_END --> <div><a href="https://cursor.com/agents/bc-ab53da24-b89d-4314-a060-0da474e837e9?cursor_ref=pr_footer&cursor_cta=open_in_web"><picture><source media="(prefers-color-scheme: dark)" srcset="https://cursor.com/assets/images/open-in-web-dark.png"><source media="(prefers-color-scheme: light)" srcset="https://cursor.com/assets/images/open-in-web-light.png"><img alt="Open in Web" width="114" height="28" src="https://cursor.com/assets/images/open-in-web-dark.png"></picture></a> <a href="https://cursor.com/background-agent?bcId=bc-ab53da24-b89d-4314-a060-0da474e837e9&cursor_ref=pr_footer&cursor_cta=open_in_cursor"><picture><source media="(prefers-color-scheme: dark)" srcset="https://cursor.com/assets/images/open-in-cursor-dark.png"><source media="(prefers-color-scheme: light)" srcset="https://cursor.com/assets/images/open-in-cursor-light.png"><img alt="Open in Cursor" width="131" height="28" src="https://cursor.com/assets/images/open-in-cursor-dark.png"></picture></a> </div> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Kyle Sexton <kyle-sexton@users.noreply.github.com>
cursor Bot
pushed a commit
that referenced
this pull request
Sep 28, 2026
…e chain (#4684) (#4714) <!-- CURSOR_AGENT_PR_BODY_BEGIN --> Closes #4684 ## Summary Bash/PowerShell PreToolUse refuses (exit 2) commands with more than 256 command/process substitutions before any guard is sourced. `run-guards.sh --max-substitutions 256` (text-only count). Timed-out hooks fail open ([hooks timeouts](https://code.claude.com/docs/en/hooks#timeouts)). `guardrails` → **0.37.4** (serialize above #4699 0.37.3; series 4684→4682→4685→4678). ## Test plan - [x] Issue payloads ~39 ms rc 2; at-cap benign still runs (per implementer) <!-- CURSOR_AGENT_PR_BODY_END --> <div><a href="https://cursor.com/agents/bc-ab53da24-b89d-4314-a060-0da474e837e9?cursor_ref=pr_footer&cursor_cta=open_in_web"><picture><source media="(prefers-color-scheme: dark)" srcset="https://cursor.com/assets/images/open-in-web-dark.png"><source media="(prefers-color-scheme: light)" srcset="https://cursor.com/assets/images/open-in-web-light.png"><img alt="Open in Web" width="114" height="28" src="https://cursor.com/assets/images/open-in-web-dark.png"></picture></a> <a href="https://cursor.com/background-agent?bcId=bc-ab53da24-b89d-4314-a060-0da474e837e9&cursor_ref=pr_footer&cursor_cta=open_in_cursor"><picture><source media="(prefers-color-scheme: dark)" srcset="https://cursor.com/assets/images/open-in-cursor-dark.png"><source media="(prefers-color-scheme: light)" srcset="https://cursor.com/assets/images/open-in-cursor-light.png"><img alt="Open in Cursor" width="131" height="28" src="https://cursor.com/assets/images/open-in-cursor-dark.png"></picture></a> </div> Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Kyle Sexton <kyle-sexton@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #4528
Summary
Bash|PowerShell PreToolUse fails closed on commands over 16384 chars before any guard tokenizes; parse-once share across the row; tokenizer made linear. 70KB heredoc: main ~133s (fail-open past 60s timeout) → branch ~61ms block.
Vendors
hook-utilsinto carrier plugins (patch bumps).guardrails→ 0.37.3.Sources
Test plan
Notes
Large multi-plugin bump — serialize vs other open guardrails/hook-utils PRs. Related follow-ups #4684 et al. in flight.