Hooks: Only Explicit Deny Blocks
Verifying lifecycle events, matchers, PreToolUse blocking, and fail-open semantics on errors
THE QUESTION THIS PAGE ANSWERS
ANSWER FIRSTWhat is the key idea behind “Hooks: Only Explicit Deny Blocks”?
Verifying lifecycle events, matchers, PreToolUse blocking, and fail-open semantics on errors
Make the claim earn its place. Use this page as a decision aid, not a definition to memorize. Connect the idea to one real task, one observable result, and one failure that would change your mind.
Write one question you could answer with evidence after trying this idea.
A conclusion that sounds complete but leaves the key assumption untested.
Hooks: Explicit Deny to Block
Think of Hooks as programmable checkpoints on events. PreToolUse can return an explicit deny; process crashes, timeouts, and unparseable output all go fail-open, letting the tool call proceed.
Learning Objectives
Distinguish Two Types of Outcomes
Identify explicit Deny versus Hook execution failure — they produce opposite results for the tool call.
Understand Event Matching
Master the matcher's exact name, regex pattern, and Bash compatibility alias.
Write Testable Configuration
Configure a command Hook following the user guide's JSON structure and design four fault-path tests.
The Decision Path of a Single PreToolUse
The Event Surface in Source Code
Eight Main-Flow Checkpoints
SessionStart, SessionEnd, Stop, StopFailure, PreToolUse, PostToolUse, PostToolUseFailure, PermissionDenied. Only PreToolUse has is_blocking() returning true.
Seven Extended Checkpoints
UserPromptSubmit, Notification, SubagentStart, SubagentStop, compatibility alias SubagentEnd, PreCompact, PostCompact.
"Event Triggered" ≠ "Controls the Main Flow"
The event enum defines trigger points; is_blocking() separately declares blocking capability. When reading the event list, also trace how results are returned to the caller.
Block vs. Fail-open Matrix
deny2allow, exit code 2Security Implication: Hooks are appropriate for policy advisories, auditing, and recoverable pre-checks. When enforcement guarantees are required, the permission layer and sandbox should also be used. Source code comments explicitly require that Hook failures must not break tool availability.
Real Source Evidence
Failure Defaults to Allow
match result {
HookRunnerResult::Decision(
HookDecision::Deny { reason, .. }
) => {
return PreToolUseResult {
decision: HookDecision::Deny { ... },
results: run_results,
};
}
HookRunnerResult::Failed(err) => {
tracing::warn!(
error = %err,
"hook failed; ignoring (fail-open)"
);
}
_ => {}
}
crates/codegen/xai-grok-hooks/src/dispatcher.rs
Matching and Exit Codes
pub const DENY_EXIT_CODE: i32 = 2;
pub fn matches(&self, tool_name: &str) -> bool {
self.regex.is_match(tool_name)
|| self.matches_compat_alias(tool_name)
}
The compatibility mapping lets Bash in configuration hit the internal tool name run_terminal_command. Matchers are compiled from regex; the user guide examples use tool names.
Configuration Written in the Real JSON Structure
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "bin/safe-shell-guard.sh",
"timeout": 5
}
]
}
]
}
}
The configuration hierarchy is "event → matcher group → handler list". Commands receive the event envelope via stdin; a valid JSON decision takes priority — if no valid JSON is present, the exit code is interpreted, with exit code 2 expressing denial. Global Hooks live in ~/.grok/hooks/; project Hooks live in .grok/hooks/ and are controlled by folder trust. Reserved environment variables are filtered out, and unresolved variables cause an error before startup.
Lab Exercise: Verify Four Paths
Deliverable
Config, script, test log
- Configure a
PreToolUsecommand Hook matchingBash. - Make the script return JSON
denyforrm -rfand record the blocked tool result. - Successively trigger exit code 1, timeout, and invalid stdout — verify all three go allowed and produce warnings.
- Change the exit code to 2, then verify that invalid stdout can still reach the explicit deny path.
- Write a one-sentence boundary statement: which policy must be moved to the permission layer or sandbox.
To judge whether a Hook is safe, ask two questions: can it express an explicit deny, and what does the main flow do when the Hook itself fails? Grok Build's answer is clear — explicit deny blocks, Hook failure goes fail-open.
Source Snapshot Note: This page is based on the hooks crate, user guide, and example configurations from the local grok-build-main snapshot. Code excerpts are for teaching purposes, with log fields and error wrappers omitted; event names, JSON hierarchy, exit codes, and decision semantics match the source.
Where the risk boundary sits in “Hooks: Explicit Deny to Block”
“Think of Hooks as programmable checkpoints on events.” moves security beyond telling a model not to make mistakes. The real protection is ensuring that a mistaken judgment cannot become an irreversible result through permissions, data, or the environment.
Separate model suggestions from real authority
In the flow described by “Identify explicit Deny versus Hook execution failure — they produce opposite results for the tool call”, check what the user may request, what the model may suggest, what the tool actually permits, and who can approve a write or send action. Web pages, documents, and tool results can carry untrusted instructions; looking like documentation does not grant them authority.
- Configure a PreToolUse command Hook matching Bash
- Make the script return JSON deny for rm -rf and record the blocked tool result
- Successively trigger exit code 1, timeout, and invalid stdout — verify all three go allowed and produce warnings
Security includes failure and recovery
Use “To judge whether a Hook is safe, ask two questions: can it express an explicit deny, and what does the main flow do when the Hook itself fails?” for a reverse exercise: add bad input, a missing credential, or an approval that never arrives. Confirm that the system refuses, pauses, and leaves a trace instead of executing to completion.
From “Hooks: Explicit Deny to Block” to “Distinguish Two Types of Outcomes”
“Hooks: Explicit Deny to Block” grounds the problem in “Think of Hooks as programmable checkpoints on events. PreToolUse can return an explicit deny; process crashes, timeouts, and unparseable output all go fail-open, letting the tool call proceed”. “Distinguish Two Types of Outcomes” then moves it toward “Identify explicit Deny versus Hook execution failure — they produce opposite results for the tool call”. Together, they show that the lesson is not just a conclusion to remember, but a claim with conditions.
Carry the judgment into the next situation
For security, separate what the model wants to do from what the system permits. Check data boundaries, tool permissions, human confirmation, and recovery after failure.
- “Hooks: Explicit Deny to Block”: Think of Hooks as programmable checkpoints on events. PreToolUse can return an explicit deny; process crashes, timeouts, and unparseable output all go fail-open, letting the tool call proceed
- “Distinguish Two Types of Outcomes”: Identify explicit Deny versus Hook execution failure — they produce opposite results for the tool call
- “The closing point”: Write a one-sentence boundary statement: which policy must be moved to the permission layer or sandbox
The final “The closing point” brings the discussion to “Write a one-sentence boundary statement: which policy must be moved to the permission layer or sandbox”. The useful thing to carry forward is knowing which judgments must be revisited when input, scale, or risk changes.
I turned one judgment from this article into a small experiment I could run today. Knowing what to observe next is more useful than simply remembering the conclusion.
After reading this, I first looked for the conditions behind the idea instead of copying the method into a project. That order made the later trade-offs much clearer.
When this judgment reaches real work, which constraint should be added first? I am curious which step matters most between reading and the first practical attempt.
No discussion on this article yet.