Back to Blog
Architecture 2026-06-04

The Case for Blocking HTTP Approvals

Why Iddio intentionally hangs HTTP connections while waiting for human approval instead of building an async negotiation protocol, and why simplicity often beats correctness in proxy design.

The Request-Response Paradox

When building an interception proxy that requires out-of-band human approval for specific operations, the immediate architectural instinct is to reach for asynchronous negotiation.

The standard playbook looks like this:

  1. Client makes a sensitive request.
  2. Proxy intercepts, returns an HTTP 403 or a custom 40x status code with an Approval-Required payload containing a token.
  3. Client parses the response, suspends its operation, and begins polling a status endpoint with the token.
  4. Human approves the request via Slack or a dashboard.
  5. Client's next poll returns Approved.
  6. Client re-submits the original request, this time including the approval token.

This design is "correct." It adheres perfectly to HTTP semantics, prevents connection pooling exhaustion, and cleanly separates the authentication/authorization phase from the execution phase. It is also entirely the wrong design for an infrastructure gateway.

The Reality of AI Agents

Iddio sits between autonomous AI agents and critical infrastructure APIs (Kubernetes, AWS, Terraform). We don't control the clients. We can't force kubectl, the AWS CLI, or an MCP client to implement a custom async approval handshake.

If we return a 403 with a JSON payload asking the client to poll, the client will simply crash with Error: Forbidden. The agentic loop will then attempt to debug the 403, hallucinate a solution involving new IAM roles, and spiral into an unrecoverable state.

We needed a solution that required zero client-side changes. The agent needed to believe it was talking to a slow, but compliant, upstream API.

Embracing the Hang

Our solution is intentionally crude: when an agent makes a request that requires human approval, Iddio simply stops reading from the socket and hangs the connection.

Behind the scenes:

  1. The command classifier assigns the request a risk tier (e.g., kubectl delete pod → modify), and the policy engine returns an escalate decision.
  2. The proxy sends an approval request via the daemon's IPC socket to the desktop app prompt or the iddio approval allow|deny CLI.
  3. The goroutine handling the client connection intentionally blocks on the approval's completion channel.
  4. From the agent's perspective, the cluster is just slow.
  5. When the human clicks "Approve," the channel unblocks, the proxy forwards the request to the upstream server, and the response flows back to the agent.

No client-side retries. No polling endpoints. No approval tokens for the agent to carry. The only state is an in-memory map of pending approvals inside the daemon.

The Trade-offs

This design choice carries significant implications, which we accepted:

Connection Timeouts

Standard HTTP clients eventually time out. In Iddio, the broker enforces a 30-second DefaultTimeout. If the human approver does not respond within this window, the proxy unblocks, returning an HTTP 403 Deny to the client with a distinct timed_out audit verdict. When the agent inevitably retries, it receives a fresh prompt; there is no request deduplication across retries.

Resource Exhaustion

Hanging connections consume file descriptors and memory on the proxy. A misbehaving agent in a tight loop could exhaust the proxy's resources by spawning thousands of pending approval requests.

Our mitigation: We manage real bounds through the 30-second budget, a sweeper eviction process for stale approvals, and client-disconnect cancellation. There is explicitly no rate limiting today.

Connection Maintenance

Proxies and load balancers between the agent and Iddio might aggressively reap idle connections.

Our mitigation: Iddio runs as a local daemon over the loopback interface and speaks HTTP/1.1 (ALPN default). Because the connection never leaves the local machine, intermediary infrastructure dropping idle connections is not a concern.

Simplicity Wins

By choosing to block the HTTP connection, we entirely eliminated the need for an "agent-side component." The agent simply gets a standard kubeconfig or environment variable. The complexity of human escalation is completely transparent to the caller.

In proxy design, developers often optimize for protocol purity at the expense of client compatibility. We chose the opposite. By treating the network as a temporal buffer, we built a zero-trust gateway that works perfectly with standard, unmodified CLI tools. Sometimes, the best state machine is no state machine at all.

Try It Yourself

Iddio is open source. Deploy a zero-trust command proxy for your AI agents in minutes.