Last reviewed
Correct answer: C. Stdout carries the JSON response to Cursor, so the extra text leaves it unparseable; the hook counts as failed, and a failed hook allows the action through unless it is marked fail-closed.
Explanation
The principle — A Cursor hook is a separate process rather than a function inside the editor. Cursor spawns the command, writes the event to its stdin as JSON and reads the reply from its stdout as JSON. Stdout is therefore a protocol channel, not a log. The exit code carries meaning alongside it: zero means the run succeeded and the JSON output should be used, two blocks the action outright, and any other code, a crash, a timeout or output that fails to parse counts as a hook failure.
Why the key is correct — The progress line lands on the same stream that carries the response, so what Cursor reads is no longer valid JSON. That is a hook failure, and hook failures fail open by default: the action proceeds. Nothing announces it. The configuration still lists the scanner, the file is still on disk, the team still believes commands are being checked, and every risky command sails through. Two fixes follow, and they are independent. Send diagnostics to stderr or to a file so that stdout carries the JSON alone. Then set failClosed to true on a security-critical hook, so that a crash, a timeout or malformed output blocks the action instead of waving it past. A guard whose failure mode is silence is worth auditing before you rely on it, which is why testing a hook by breaking it on purpose is time well spent.
Why the others are wrong — Treating a hook as an in-editor callback is the root error here; the process boundary is what makes stdout precious, and the matcher inspects the command rather than the script. A malformed response also does not tear down the hook chain: the process is spawned again for the next event and fails identically, which is why the problem persists rather than announcing itself once. And the exit code does not override the body — zero is precisely the code that tells Cursor to trust the JSON it just read.
Remember this — Stdout belongs to the protocol, and a broken hook lets work through unless you have said otherwise.
Sources — Cursor's Hooks documentation.
Sources
“Hooks are spawned processes that communicate over stdio using JSON in both directions.”
Practise 10 questions on this topic
Take Cursor Basics — Timed Test 1 (10 questions) — scored instantly, explanation for every question, no login.