Skip to content

fix(hooks): fail closed when a PRE_TOOL_USE enforcement hook crashes#16

Merged
tao-hpu merged 1 commit into
fim-ai:masterfrom
wcboy:fix/hook-fail-closed
Jun 13, 2026
Merged

fix(hooks): fail closed when a PRE_TOOL_USE enforcement hook crashes#16
tao-hpu merged 1 commit into
fim-ai:masterfrom
wcboy:fix/hook-fail-closed

Conversation

@wcboy

@wcboy wcboy commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

What

PRE_TOOL_USE hooks now fail closed: if a hook's handler raises, the tool call is denied by default instead of allowed. A new fail_open flag lets non-enforcement hooks (rate limiter, loggers) keep the previous fail-open behavior. POST/SESSION hooks are unchanged.

Why

Hook.execute caught any handler exception and returned HookResult(allow=True) unconditionally — so a crashing enforcement hook (e.g. FeishuGateHook, which holds a tool call behind a human approval card) would silently let the tool through. The module docstring calls hooks a "deterministic enforcement layer ... [that] cannot be bypassed", which a stray exception turning a gate into a no-op contradicts.

This is a deliberate design-posture change, so flagging it explicitly: the old comment ("Hooks must NEVER crash the agent ... a permissive HookResult (allow=True) is returned") was an availability-first choice. This PR preserves that property for hooks that aren't security boundaries (fail_open=True, set on the built-in rate_limiter) while defaulting enforcement gates to deny-on-error. Happy to narrow the split (e.g. opt-in fail-closed only on gate subclasses) if you'd prefer.

Type

  • Bug fix
  • Security patch

Checklist

  • Tests added — fail_open flag, PRE fail-closed default, POST non-blocking, chain behavior
  • uv run pytest -m "not docker" — 3780 passed
  • mypy --strict clean on changed source files
  • Changelog updated (EN; translations left to the pre-commit pipeline)
  • ruff check — this change introduces no new lint; two pre-existing issues (UP035 in hooks.py, import-sort in test_agent_hooks.py) are left untouched to keep the diff surgical

A PRE_TOOL_USE hook that raised an exception previously returned
allow=True, so a crashing enforcement gate (e.g. an approval hook)
silently let the tool call through — a broken security boundary became a
bypass.

PRE hooks now deny by default when their handler raises. Non-enforcement
hooks (rate limiter, loggers) opt into the prior fail-open behavior via a
new `fail_open` flag. POST/SESSION hooks are unaffected (they cannot block
execution). Updates the two hook-error tests that previously asserted the
fail-open behavior and adds coverage for the fail-closed / fail-open split.
@tao-hpu tao-hpu merged commit 40d46ee into fim-ai:master Jun 13, 2026
tao-hpu added a commit that referenced this pull request Jun 13, 2026
…ity fixes

- README all-contributors: add wcboy (code), Joshua-Medvinsky (security)
- Security Hall of Fame: first entries (FailSafe SSRF findings)
- changelog: move hook fail-closed + add SSRF fixes under [Unreleased]
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.

2 participants