Writing ·
How should AI agent policy hooks fail when the policy service is unavailable?
For a consequential agent action, a missing policy decision must mean do not perform the action: bound the policy call with a timeout, accept only a validated verdict, and turn a missing, invalid, or failed decision into a durable, recorded deny.
By Youssef Hemimy · agent safety · authorization · AgentOps
For a consequential agent action, a missing policy decision must mean “do not perform the action.” Give the policy call a bounded timeout, accept only a validated decision shape, synthesize a named deny when the policy path fails, and record the event with the action identity. A policy outage should create recovery work—not an invisible allow path.
This is a different question from whether a new tool starts default-denied. A tool may be correctly classified and still become a bypass if the runtime asks its policy hook for a decision, receives no usable answer, and proceeds anyway. OWASP's authorization guidance calls out both “Deny by Default” and “Exit Safely when Authorization Checks Fail.”
Put the policy result inside the action contract
Before a consequential tool call, make the runtime able to answer four questions without reading a model's prose:
| Contract element | What the runtime needs to know |
|---|---|
| Protected action | The tool, operation, target, and the identity or hash that binds the request. |
| Policy deadline | How long the runtime waits before declaring the policy path unavailable. |
| Valid verdict | A small, schema-checked decision such as allow, deny, or a denial that an approval path may lift. |
| Durable record | The action identity, policy outcome, failure reason, time, and eventual recovery outcome. |
The exact fields are a deployment decision. The important boundary is not: “the agent was instructed to check policy.” It is: “the host has not invoked the protected action until it has an enforceable result.”
Agent Hooks is one concrete contract that makes this boundary explicit. Its specification defines eight lifecycle interception points and requires a host to deny if it cannot construct valid context, cannot reach an interceptor, or receives an invalid verdict. It also says a host must not execute an action without the interceptors required by its declared composition profile.
Make each failure outcome boring and observable
“Fail closed” should be an implementation rule with named cases, not a slogan. The Agent Hooks specification provides a useful example: an interceptor that raises becomes host_error:interceptor_failed; a timeout becomes host_error:interceptor_timeout; and a returned value that fails validation becomes host_error:verdict_invalid. Each is substituted as a deny.
Use the same discipline even if you do not use that contract:
| Failure at the decision boundary | Enforced result | What operations should receive |
|---|---|---|
| Policy service is unreachable | Deny the protected action | A stable reason, action identity, and service-health signal. |
| Policy call times out | Deny the protected action | Timeout reason, configured deadline, and whether the action was retried. |
| Policy response is malformed or cannot be validated | Deny the protected action | Validation reason without leaking tool arguments or other sensitive payloads. |
| Policy code throws | Deny the protected action | A bounded failure classification and the failed action's identity. |
| An approval is requested but never resolves | Keep the action denied | Approval-request identity, expiry, and a clear next owner. |
The record is part of the control. Without it, an operator cannot distinguish a legitimate policy denial from a control-plane failure—or prove that a retry did not execute a different action.
The tradeoff is availability, so design the recovery path
Fail-closed handling will block legitimate work when a policy dependency is slow or unavailable. That is the point: it refuses to exchange an unknown authorization decision for an untracked side effect. But it only works in practice when the recovery workflow is also designed.
Agent Hooks' production guidance makes this tradeoff concrete: a hung interceptor halts the agent under fail-closed semantics, and it recommends choosing a timeout deliberately, configuring record persistence, and deciding how approval and composition behave.
A practical rollout looks like this:
- Classify the action. Start with writes, permission changes, external messages, payments, deployments, and other consequential effects. Keep read-only work on a separately reviewed path.
- Set a deadline and failure taxonomy. Pick a bounded timeout suitable for the action. Do not collapse timeout, invalid response, and explicit deny into one undifferentiated error.
- Bind recovery to the same request. A retry or approval must refer to the original tool, target, arguments or action hash, and policy version. A changed request needs a new decision.
- Run in observation mode only as a rollout aid. Compare expected denies with actual actions, then enable enforcement for one protected action class. Do not describe observe-only logging as protection.
- Exercise the failure paths. Test unavailable service, timeout, thrown exception, malformed result, expired approval, duplicate retry, and a changed request after approval.
- Alert on the control's health. A rising failure-deny rate is both an availability event and a safety event. Give it a named owner and runbook.
Human approval gates for AI agents is the adjacent pattern when a person may lift a denial. The approval needs to be bound to the concrete action—not a vague “continue” button. For the action-boundary implementation, use production agent tool contracts.
A policy hook is not a security boundary by itself
Do not overclaim what this pattern buys you. Agent Hooks describes itself as a cooperative contract, not a security boundary: its host is trusted, a host can skip interception points or ignore verdicts, and the contract does not promise complete mediation for direct execution or background paths.
Sources
FAQ
Should every policy lookup fail closed?
Apply this rule to the decision points that protect consequential actions. The classification is yours, but an unknown policy result must not silently authorize an action that depends on that result.
Does a timeout mean the policy denied the request?
No. Preserve the distinction. A timeout is a control-path failure that the runtime treats as a deny for enforcement, while the record should identify it as a timeout for diagnosis and recovery.
Can a human override a failure-deny?
Yes, if the workflow deliberately permits it. Bind that approval to the exact request and give it an expiry. A different target or argument set requires a new policy and approval decision.
Does a conformant hook prevent all bypasses?
No. The Agent Hooks documentation explicitly limits its guarantees to a cooperating host and says it is not complete mediation or a security boundary.
Building something that has to hold up?
We do this work for teams — agent reliability hardening, custom MCP servers, and full-stack AI systems built to survive production.