Skip to content

Require Human Approval for Risky Agent Actions: A Policy Pattern

Learn how to require approval for risky agent actions at the egress boundary with policy-as-code gates and audit-ready receipts. Request Agent G access.

By Agent G Engineering7

To require approval for risky agent actions, classify every outbound tool call by blast radius, deny the irreversible ones by default, and hold them at the network egress point until a named human approves. Because the gate lives outside the agent process, a poisoned prompt or a hallucinated plan cannot talk its way past it.

This is the implementation pattern behind that sentence: how to tier actions, where the gate belongs, how to pause an agent before execution without breaking HTTP clients, and what the approval record must contain to survive an audit.

Why in-agent approval prompts are not a control

Most agent frameworks ship some form of confirmation hook: a callback before tool execution, a human_input node, an MCP client dialog that asks the user to allow a tool. These are useful for developer experience. They are not security controls, for three reasons.

  • They live inside the trust boundary the attacker already owns. If untrusted content reached the model context, that same content can influence which branch the agent takes, including the branch that decides an action is low risk and skips confirmation.
  • They are per-framework and per-client. A LangGraph interrupt does nothing for a background CrewAI worker, a shell command spawned by a coding agent, or a raw requests.post inside a custom tool.
  • They produce no independent evidence. The log that says a human approved is written by the same process that took the action. An auditor reasonably discounts self-attested logs.

The fix is not to remove in-agent prompts. It is to place the enforcing gate one layer down, on the wire, where every framework, every SDK, and every subprocess has to pass through the same policy engine.

Where the approval gate belongs

PlacementSurvives prompt injectionCovers all frameworks and subprocessesIndependent audit evidence
Framework callback (LangGraph interrupt, CrewAI human input)No, decision logic shares the compromised contextNo, one framework onlyNo, self-reported
MCP client confirmation dialogPartially, tool description can be misleadingNo, MCP transport onlyWeak, client-side
Application code wrapper around tool functionsSometimes, if the wrapper cannot be bypassedNo, misses shell and library callsNo, same process
Egress proxy gate (Agent G)Yes, policy evaluated outside the agentYes, anything that opens a socketYes, out-of-band signed records

How to require approval for risky agent actions in five steps

  1. Inventory the outbound calls. Run the agent in observe mode behind a proxy for a week and collect method, host, path, and argument shape for every request. You cannot tier what you have not seen. Shadow endpoints show up here almost immediately.
  2. Tier by reversibility, not by tool name. The question is not is this the payments tool, it is can this be undone in under five minutes without a human. A GET /v1/customers is auto-allow. A POST /v1/transfers is escalate. A DELETE against production storage is block, full stop. See policy-as-code guardrails for how to express this as versioned rules.
  3. Write default-deny for the escalate tier. An unmatched destructive verb should fail closed. If a new tool appears next sprint, it should require approval by default rather than silently inheriting allow. Pair this with a default-deny egress allowlist so unknown hosts are never reachable at all.
  4. Bind the approval to the exact request. Hash the method, host, path, and canonicalized body. The approval token authorizes that hash only. If the agent retries with a different amount or a different recipient, the hash changes and the call is gated again. This is what stops approve-then-swap.
  5. Emit an approval record out of band. Approver identity, decision, timestamp, request hash, policy version, and rule ID, written to your SIEM from the proxy, not from the agent. That record is the artifact you hand to compliance.

Writing the approval gate for LLM tool calls

Express the gate as declarative rules in Git, reviewed like any other infrastructure change. A workable shape looks like this:

rules:
  - id: payments-transfer-escalate
    match:
      host: 'api.stripe.com'
      method: 'POST'
      path_prefix: '/v1/transfers'
    action: 'escalate'
    approvers: ['group:finance-oncall']
    quorum: 2
    ttl_seconds: 900
    bind: ['method', 'host', 'path', 'body_sha256']
  - id: prod-db-destructive-block
    match:
      body_regex: '(?i)\b(drop|truncate)\s+table\b'
    action: 'block'

Three details matter more than the syntax. Quorum lets you demand dual control on the highest tier. TTL prevents an approval from sitting open for hours and being consumed by an unrelated retry. Bind is the anti-replay mechanism described in step four.

How to pause an agent before execution without breaking the client

The hard engineering problem is not the decision, it is the hold. An HTTP client inside a tool call expects a response within its timeout. There are three viable patterns.

  • Hold the connection. The proxy accepts the request, keeps the socket open, and forwards it on approval. Simple and transparent to the agent, but bounded by client timeouts, typically 30 to 120 seconds. Best for interactive workflows where a human is already watching.
  • Fail closed with a structured deny. Return 403 with a machine-readable body containing an approval URL and a correlation ID. The agent learns that the action is pending, reports back to its operator, and stops. This is the safest default for long-running autonomous jobs, and it maps cleanly onto retry logic.
  • Deferred execution. The proxy returns 202 Accepted with a ticket, holds the request server side, and replays it verbatim on approval using the bound hash. The agent polls the ticket. This preserves the action even if the agent process dies, which matters for batch and CI workloads.

Whichever you pick, make the deny body descriptive. An agent that receives an opaque 403 will often improvise: try a different host, encode the payload, or reach for an alternate tool. That improvisation is exactly the behavior described in blocking destructive agent actions, and it is why a structured, honest deny outperforms a silent drop.

Making manual approval for AI agent traffic fast enough to live with

An approval gate that pages a human on every third call gets disabled within a month. Throughput discipline is part of the design.

  • Keep the escalate tier small. If more than roughly one in fifty calls escalates, your tiering is wrong, not your reviewers. Push repeated, safe patterns into auto-allow with argument constraints (for example, transfers under a threshold to previously seen recipients).
  • Route to the right queue. Finance approves payments, platform approves infrastructure mutations, data owners approve bulk exports. A single firehose channel becomes noise and then becomes rubber-stamping.
  • Give approvers full context. The approval prompt should show the resolved host, the method, the diff or the exact body, the agent identity, and the triggering task. Approving a request you cannot read is theater.
  • Set a deny-on-timeout default. If nobody responds within the TTL, the action is denied and logged as expired. Fail open here and the whole pattern collapses.
  • Instrument the gate itself. Track approval latency, approval rate per rule, and expired requests. A rule approved 100 percent of the time is a candidate for auto-allow. A rule denied 100 percent of the time should become a hard block.

Session-scoped approvals help too: approve a class of action for one agent run rather than one request, with a short TTL and a hard cap on invocations. That is the compromise that keeps coding agents and data pipelines usable while still requiring a human at the boundary.

What the approval record must contain

Treat every gated decision as an evidence artifact. At minimum, capture the agent identity (workload identity, not a shared API key), the full request tuple, the matched rule ID and policy commit SHA, the approver identity and authentication method, the decision and timestamp, the TTL, and the final upstream status code. Written from the proxy, this record is independent of the agent and therefore usable as compliance evidence. The deeper treatment of designing the human loop itself, including approver fatigue and escalation policy, is in our guide to human-in-the-loop approval for AI agents.

Frequently Asked Questions

What is the difference between blocking and requiring approval?

Blocking is a static policy decision: the action is never permitted, and the agent receives a deny immediately. Requiring approval defers the decision to a human at runtime. Use blocking for actions no agent should ever take, and approval for legitimate but high-blast-radius operations like payments or production writes.

Can I require approval for risky agent actions without changing agent code?

Yes. Point the agent at an egress proxy through standard HTTPS_PROXY environment variables or a Kubernetes egress route, and enforce policy there. No SDK wrappers, no callbacks, no framework coupling. Anything the agent process opens a socket to passes through the same gate.

How do I stop an agent from retrying around a pending approval?

Bind approvals to a hash of the request and fail closed on unmatched destinations. Combine with per-agent rate limits so repeated attempts against the same rule trigger an alert rather than eventually succeeding through a variant payload or an alternate host.

Does an approval gate add meaningful latency?

For auto-allow traffic, policy evaluation is sub-millisecond and adds no perceptible overhead. Latency appears only on escalated calls, where the wait is human response time by design. Keeping the escalate tier under a few percent of traffic keeps aggregate impact negligible.

Bringing it together

If you require approval for risky agent actions inside the agent, you are asking a compromised system to police itself. Move the gate to the egress boundary, tier actions by reversibility, bind approvals to exact requests, and write the decision record out of band. That combination is deterministic, framework-agnostic, and auditable, which is exactly what a security review is going to ask for.

Agent G enforces this pattern as a drop-in proxy: default-deny egress, argument-level inspection, human-in-the-loop approval with quorum and TTL, and signed action records streamed to your SIEM. See how Agent G works, review the MCP gateway for tool-call enforcement, or compare approaches on our alternatives page.

Request access to the Agent G private beta and put a real approval gate in front of your agents before the first irreversible call.

Agent G

Drop-in guardrails for the agentic era.

Intercept every network call your AI makes. Block destructive actions, enforce approvals, log everything.

Request access