feat: add block-no-verify PreToolUse hook to prevent agents from bypassing git hooks#455
feat: add block-no-verify PreToolUse hook to prevent agents from bypassing git hooks#455tupe12334 wants to merge 1 commit intomoltis-org:mainfrom
Conversation
Prevents agents from bypassing git hooks via the hook-skip flag.
Greptile SummaryThis PR adds Key observations:
Confidence Score: 2/5
Important Files Changed
Sequence DiagramsequenceDiagram
participant Agent as Claude Agent
participant Hook as PreToolUse Hook
participant npx as npx (block-no-verify@1.1.2)
participant npm as npm Registry
participant Bash as Bash Tool
Agent->>Hook: Any Bash command (git or otherwise)
Hook->>npx: Execute with tool_input via stdin
alt Package not in local cache
npx->>npm: Fetch block-no-verify@1.1.2
npm-->>npx: Package (or timeout/error)
end
npx->>npx: Parse tool_input.command
alt Command contains --no-verify / -n in git context
npx-->>Hook: Exit 2 (BLOCK)
Hook-->>Agent: Bash command blocked
else Command is safe
npx-->>Hook: Exit 0 (ALLOW)
Hook->>Bash: Execute command
Bash-->>Agent: Result
end
Last reviewed commit: "feat: add block-no-v..." |
| { | ||
| "type": "command", | ||
| "command": "npx block-no-verify@1.1.2" | ||
| } |
There was a problem hiding this comment.
Add
--yes flag to prevent interactive prompt
npx without --yes (or -y) can prompt the user to confirm installation when the package is not already in the local npm cache, or on certain npm versions. In the non-interactive context of a Claude Code hook, this prompt would cause the hook — and therefore the entire Bash tool — to hang indefinitely on a fresh machine or CI environment.
| } | |
| "command": "npx --yes block-no-verify@1.1.2" |
| "matcher": "Bash", | ||
| "hooks": [ | ||
| { | ||
| "type": "command", | ||
| "command": "npx block-no-verify@1.1.2" | ||
| } |
There was a problem hiding this comment.
Hook fires on every Bash invocation, not just git commands
The "matcher": "Bash" means block-no-verify is executed before every Bash tool call — file reads, test runs, npm install, build commands, etc. While block-no-verify should exit 0 quickly for non-git commands, npx itself adds startup overhead on each call, and critically, the first invocation on any machine without a warm npm cache will require a network round-trip to the npm registry. If the registry is unreachable (firewall, offline environment, network interruption), this hook can hang, blocking the entire Bash tool.
Consider whether the matcher should be more targeted (e.g. using a wrapper script that only invokes the tool when the command starts with git) or adding a network timeout to the hook execution.
| "type": "command", | ||
| "command": "npx block-no-verify@1.1.2" | ||
| } |
There was a problem hiding this comment.
External package authored by the PR submitter runs in a privileged hook position
The PR description discloses (commendably) that the author is also the maintainer of block-no-verify. Nonetheless, this change introduces a third-party npm package — maintained by the same person opening the PR — that:
- Runs before every Bash command executed by the Claude agent.
- Can exit 2 to block any Bash command entirely.
- Receives the full Claude Code hook stdin payload (including
tool_input.command) on each invocation.
While pinning to @1.1.2 prevents unintended upgrades to future versions, it does not protect against a compromise of that specific published artifact on the npm registry. The package has minimal adoption (1 GitHub star at time of review), which lowers the scrutiny it receives from the community.
It is worth confirming with the team that the package's source at that exact version has been independently reviewed before merging, given the privileged position it occupies in the agent's execution path.
Summary
Adds
block-no-verify@1.1.2as aPreToolUseBash hook in.claude/settings.json, alongside the existingPostToolUsehooks.Details
When an agent runs
git commitorgit pushwith the hook-bypass flag, it silently disables pre-commit, commit-msg, and pre-push hooks.block-no-verifyreadstool_input.commandfrom the Claude Code hook stdin payload, detects the hook-bypass flag across all git subcommands, and exits 2 to block. The existingPostToolUsehooks are preserved unchanged.Closes #454
Disclosure: I am the author and maintainer of
block-no-verify.