From d1be9272f71b8ed5f6e6ca30dee31150a06144b2 Mon Sep 17 00:00:00 2001 From: willwang Date: Tue, 25 Aug 2026 13:05:21 +0800 Subject: [PATCH] fix: block stop gate on malformed hook input --- plugins/codex/scripts/stop-review-gate-hook.mjs | 11 ++++++++++- tests/runtime.test.mjs | 13 +++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/plugins/codex/scripts/stop-review-gate-hook.mjs b/plugins/codex/scripts/stop-review-gate-hook.mjs index 2346bdcf4..4c0b6d481 100644 --- a/plugins/codex/scripts/stop-review-gate-hook.mjs +++ b/plugins/codex/scripts/stop-review-gate-hook.mjs @@ -140,7 +140,16 @@ function runStopReview(cwd, input = {}) { } function main() { - const input = readHookInput(); + let input; + try { + input = readHookInput(); + } catch { + emitDecision({ + decision: "block", + reason: "The stop review gate could not read or parse hook input; refusing to fail open." + }); + return; + } const cwd = input.cwd || process.env.CLAUDE_PROJECT_DIR || process.cwd(); const workspaceRoot = resolveWorkspaceRoot(cwd); const config = getConfig(workspaceRoot); diff --git a/tests/runtime.test.mjs b/tests/runtime.test.mjs index 8f276835b..2f50725b1 100644 --- a/tests/runtime.test.mjs +++ b/tests/runtime.test.mjs @@ -1979,6 +1979,19 @@ test("stop hook runs a stop-time review task and blocks on findings when the rev assert.match(status.stdout, /Codex Stop Gate Review/); }); +test("stop hook blocks when hook input is malformed JSON", () => { + const blocked = run(process.execPath, [STOP_HOOK], { + cwd: ROOT, + input: "{not-json" + }); + + assert.equal(blocked.status, 0, blocked.stderr); + assert.deepEqual(JSON.parse(blocked.stdout), { + decision: "block", + reason: "The stop review gate could not read or parse hook input; refusing to fail open." + }); +}); + test("stop hook logs running tasks to stderr without blocking when the review gate is disabled", () => { const repo = makeTempDir(); initGitRepo(repo);