Description
stop-review-gate-hook.mjs parses hook stdin before entering the review-gate logic. A malformed non-empty JSON payload throws an uncaught SyntaxError, exits with status 1, and emits no decision: "block" response. When the host treats a crashed Stop hook as having supplied no block decision, the review gate can fail open.
Reproduction
With plugin 1.0.2:
printf '%s' '{not-json' | node scripts/stop-review-gate-hook.mjs
Observed result:
SyntaxError: Expected property name or '}' in JSON at position 1
at JSON.parse
at readHookInput (.../stop-review-gate-hook.mjs:26:15)
at main (.../stop-review-gate-hook.mjs:143:17)
The process exits 1 without emitting hook JSON.
Root cause
readHookInput() calls JSON.parse(raw) without a catch, and main() calls readHookInput() before any fail-closed handling:
function readHookInput() {
const raw = fs.readFileSync(0, "utf8").trim();
if (!raw) return {};
return JSON.parse(raw);
}
Expected behavior
Any failure to read or parse Stop-hook input should emit a valid fail-closed response, for example:
{"decision":"block","reason":"The stop review gate could not parse hook input; refusing to fail open."}
A regression test should feed malformed non-empty stdin and assert exit 0 plus a valid decision: "block" payload.
Related
Environment
- Codex plugin: 1.0.2
- Claude Code: 2.1.241
- Node.js: 24.17.0
- OS: WSL2 / Linux
Description
stop-review-gate-hook.mjsparses hook stdin before entering the review-gate logic. A malformed non-empty JSON payload throws an uncaughtSyntaxError, exits with status 1, and emits nodecision: "block"response. When the host treats a crashed Stop hook as having supplied no block decision, the review gate can fail open.Reproduction
With plugin 1.0.2:
Observed result:
The process exits 1 without emitting hook JSON.
Root cause
readHookInput()callsJSON.parse(raw)without a catch, andmain()callsreadHookInput()before any fail-closed handling:Expected behavior
Any failure to read or parse Stop-hook input should emit a valid fail-closed response, for example:
{"decision":"block","reason":"The stop review gate could not parse hook input; refusing to fail open."}A regression test should feed malformed non-empty stdin and assert exit 0 plus a valid
decision: "block"payload.Related
readHookInput()failure mode (EAGAIN). The malformed-JSON case is deterministic and specifically requires fail-closed Stop-gate behavior.Environment