Skip to content

fix: guardrail hooks fail-open instead of fail-closed#580

Merged
gm3dmo merged 1 commit into
gm3dmo:mainfrom
kwacky1:fix/hooks-fail-open
Jun 9, 2026
Merged

fix: guardrail hooks fail-open instead of fail-closed#580
gm3dmo merged 1 commit into
gm3dmo:mainfrom
kwacky1:fix/hooks-fail-open

Conversation

@kwacky1

@kwacky1 kwacky1 commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

Problem

The guardrail hooks in copilot-plugin/hooks/_common.sh use set -e, which causes the script to exit with a non-zero code if anything unexpected happens before reaching the toolName != bash → exit 0 check.

When the Copilot CLI invokes these hooks for non-bash tools (e.g. Zendesk MCP, GitHub MCP, or any other MCP tool call), the hook errors out rather than returning a clean exit. The CLI interprets a hook error as a denial, which blocks all tool calls — including reads, shell commands, and MCP calls.

Fix

  1. Remove set -e
  2. Add trap 'exit 0' ERR — fail-open on unexpected errors
  3. Add early validation: if input is empty or not valid JSON, exit 0 immediately

These hooks only guard against destructive bash operations — they should never interfere with non-bash tools.

Testing

# Non-bash tool → allowed
echo '{"toolName":"get_ticket_comments","toolArgs":{"ticket_id":"123"}}' | bash hooks/guard-destructive-ops.sh
# exit 0 ✅

# Empty input → allowed
echo '' | bash hooks/guard-destructive-ops.sh
# exit 0 ✅

# Safe bash → allowed
echo '{"toolName":"bash","toolArgs":{"command":"echo hello"},"cwd":"/tmp"}' | bash hooks/guard-destructive-ops.sh
# exit 0 ✅

# Destructive bash → denied (correctly)
echo '{"toolName":"bash","toolArgs":{"command":"./delete-a-repo.sh"},"cwd":"/tmp"}' | bash hooks/guard-destructive-ops.sh
# outputs deny JSON ✅

Fixes #579

Remove `set -e` from _common.sh and add `trap 'exit 0' ERR` so that
unexpected errors (empty input, malformed JSON, non-bash tool payloads)
result in allowing the tool call rather than blocking it.

Previously, when non-bash MCP tools (e.g. Zendesk, GitHub MCP) triggered
the preToolUse hooks, the script could error out before reaching the
'toolName != bash' check. The CLI interprets hook errors as denials,
which blocked ALL tool calls — including reads, shell commands, and MCP.

Also adds early JSON validation: if input is empty or invalid JSON, exit
immediately with allow.

Fixes gm3dmo#579

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@kwacky1 kwacky1 deployed to release1 June 9, 2026 03:57 — with GitHub Actions Active
@gm3dmo gm3dmo self-requested a review June 9, 2026 04:35

@gm3dmo gm3dmo left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me.

@gm3dmo gm3dmo merged commit b49fd2d into gm3dmo:main Jun 9, 2026
2 checks passed
@kwacky1 kwacky1 deleted the fix/hooks-fail-open branch June 9, 2026 04:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

preToolUse guardrail hooks fail-closed on non-bash tools (blocks all MCP calls)

2 participants