An agent can't be its own authority

Sandboxes limit where an agent can reach. Something outside the model has to decide whether this exact call may run, and something outside the operator has to prove what happened when it did.

Vidhi Waghela's article"Your AI agent finished the task. Can your system prove what happened?"asks a question most agent stacks cannot answer today. It is worth reading in full, and it prompted this post. Here is how we think about the answer in CloakPipe, and which parts of it we are building into the open-source core.

Where a sandbox stops

The usual first step for running an agent safely is containment. Put it in a container, restrict the network, hand it scoped credentials. That work is necessary, and it answers one question well: which systems can this process reach at all?

It does not answer the next question. Inside the sandbox, an agent holding a CRM token can patch any record that token can patch. The credential is scoped to the agent, not to the task the agent was given a minute ago. When the model proposes crm.patch on another customer's record, the sandbox lets it through, because the CRM is within reach and the token is valid.

The model chooses what to call from its context, and that context holds text from users, retrieved documents and earlier tool results. Any of those can steer it. If the model's own proposal is what authorizes the call, then the real authority is whoever last wrote into its context. That is the sense in which an agent cannot be its own authority.

A boundary decides the exact call

An action boundary sits between the model and the tool. It treats every tool call as a proposal and decides on it using only trusted inputs: the certified release the agent runs as, a contract for each tool, the task context written by the orchestrator, and signed approvals. Nothing the agent sends can change those inputs, including arguments and request metadata. To decide well, the boundary needs four things.

None of this needs the model to behave. The model can propose anything it likes. What runs is decided elsewhere.

Test both directions

There is an easy way to pass every authorization test: refuse everything. A boundary that blocks the attack and also blocks the customer's legitimate refund has not done its job; it has moved the failure somewhere less visible.

So we certify the boundary in both directions. Each test case is labelled with what should happen, allow or deny. A release must block the cases it should block and complete the authorized work it is meant to do. Under-blocking and over-refusal are separate failures with separate reasons, and a suite that is missing either kind of case cannot pass at all.

Proof that does not depend on the operator

A decision is only half the story. Afterwards, someone will ask what happened: a customer, an auditor, an incident review. A log written by the same system it describes is a claim, not proof, because whoever runs that system can edit it.

CloakPipe records each decision as a hop in a hash-chained, signed evidence ledger, bound to the hash of the certified release that made it. An approved call carries the digest of its approval, so an auditor can match the operator's receipt to the ledger entry. Reconciling an uncertain operation is recorded as its own entry, so "we checked and it went through" is evidence too. The ledger holds no raw argument values, and not even plain hashes of them, since short values like phone numbers can be recovered by brute force.

An exported bundle can be anchored at a public timestamp authority and a transparency log, so the operator cannot back-date it. An auditor then verifies it offline with published public keys, with no access to the operator's systems and no need to trust us.

Where this stands

The release gate, which refuses tool calls from an agent that is not running a certified release, and the evidence ledger are on main of the open-source core. So are tool contracts, signed approvals, operation tracking and two-way boundary certification, which landed this week. TheMCP tool gate docs show how to use them, and the certification docs describe the boundary rule.

There are limits worth stating plainly. MCP has no standard way to ask a server whether a call took effect, so reconciliation is a manual step for now. The boundary only sees calls that pass through it. And a contract is only as good as the rules written into it: the boundary enforces them exactly, but it cannot tell you that you forgot one.

Thanks to Vidhi Waghela, whose article on proving what an agent did prompted this post. CloakPipe is open source; the code is on GitHub.