fix(security): honor shell hook blocks even when message/reason is absent

_parse_response in agent/shell_hooks.py only forwarded a pre_tool_call
block directive if the hook also provided a non-empty message or reason.
When either field was missing the function returned None, causing Hermes
to treat the response as a no-op and execute the tool unconditionally.

This means a hook that outputs {"action": "block"} or {"decision": "block"}
without a reason string is silently ignored. The security boundary fails
open: tools the user intended to gate are executed anyway.

Fix: remove the message-presence guard. Honor the block unconditionally
and fall back to a default message when none is provided. Existing hooks
that already include a message or reason are unaffected.
This commit is contained in:
flamiinngo 2026-05-17 03:31:08 +01:00 committed by Teknium
parent 8e3cfdfb61
commit aeda146112

View file

@ -515,13 +515,11 @@ def _parse_response(event: str, stdout: str) -> Optional[Dict[str, Any]]:
if event == "pre_tool_call":
if data.get("action") == "block":
message = data.get("message") or data.get("reason") or ""
if isinstance(message, str) and message:
return {"action": "block", "message": message}
message = data.get("message") or data.get("reason") or "Blocked by shell hook."
return {"action": "block", "message": message}
if data.get("decision") == "block":
message = data.get("reason") or data.get("message") or ""
if isinstance(message, str) and message:
return {"action": "block", "message": message}
message = data.get("reason") or data.get("message") or "Blocked by shell hook."
return {"action": "block", "message": message}
return None
context = data.get("context")