DEV Community

Cover image for AI Agent Permissions: Why Approval Is Not Authorization
Logan for Waxell

Posted on Originally published at waxell.ai

AI Agent Permissions: Why Approval Is Not Authorization

In August 2026 Anthropic published the engineering writeup behind Claude Code's auto mode. The results section contains one sentence that does more to explain agent permissions than most of the literature on them. Describing the cases where its classifier lets a dangerous action through, the post says: "The classifier finds approval-shaped evidence and stops short of checking whether it's consent for the blast radius of the action."

Read that again with humans substituted for the classifier. It is the same failure. A reviewer sees a request that looks like something they authorized, and approves it — not because they are careless, but because the artifact in front of them is shaped like an approval and carries no scope.

That is the structural problem with agent permission prompts, and it is why adding more of them does not fix it.

The evidence: reviewers catch what looks dangerous, not what is dangerous

In August 2026 Alex Wauters published the aggregate data from a browser game in which players act as the human approver for an AI coding agent, clicking approve or deny on commands under time pressure. Across more than 40,000 runs and 409,000 individual decisions, mean accuracy was 66.3 per cent. Reviewers missed roughly one threat in three.

The interesting part is not the average. It is the distribution:

Threat category Miss rate
Obviously destructive (rm -rf /, chmod -R 777 /) 11.7%
Persistent mutation (crontab injection, git config hijack) 23.8%
Exfiltration and code execution 33.4%
Scope violations (cat ~/.aws/credentials) 35.0%

Reviewers caught the commands that look destructive nearly nine times in ten. They missed the commands that quietly move credentials out of the building roughly a third of the time. Danger and legibility are different properties, and the approval prompt renders only the second one.

The most-missed command in the dataset makes the mechanism explicit. npm run analyze was approved 64.7 per cent of the time — first out of 37 threats — because npm run is not a command, it is a pointer to a command written somewhere else. The payload lived in package.json. Pooled across three variants, script-name-wrapped payloads were missed 52.5 per cent of the time against 28.4 per cent for other exfiltration attempts. A familiar script name roughly doubled a payload's success rate, and it did so even though the game printed the malicious script in the history log directly above the prompt.

Wauters is careful about the limits of his own data, and so should anyone citing it be: roughly 34 per cent of the commands players saw were threats, far above any real workload, and players knew they were being tested. Both inflate vigilance rather than deflate it. The category ranking is what survives those caveats, not the headline percentage.

The same gap appears when you replace the human with a model

The obvious response is to take the tired human out of the loop. Anthropic has now done exactly that: on Pro, Max and Team plans, auto mode — where a classifier model reviews actions instead of a person — is the built-in starting permission mode. The reasoning is unambiguous in Anthropic's own words: manual prompts sit in the middle of the tradeoff space, "and in practice users accept 93% of them anyway."

The published numbers are good. On a curated set of 52 real overeager actions the full two-stage pipeline has a 17 per cent false-negative rate, and on 10,000 real tool calls a 0.4 per cent false-positive rate. Anthropic calls the 17 per cent "the honest number" and states plainly that auto mode "is not a drop-in replacement for careful human review on high-stakes infrastructure."

But look at why the misses happen. In most of the cases Anthropic examined, the classifier correctly identified the danger — it saw the force-push, the deletion, the infrastructure change. What it got wrong was whether anything in the session authorized that specific blast radius. "Clean up the PR" was said by the user; it does not name force-pushing. A similar action was approved earlier; one approval is not a pattern.

Swapping a fatigued human for a fresh model did not fix the join. It relocated it.

Why: an approval is an event, and authorization is a state

Both failures have the same shape, and it is architectural rather than behavioural.

A permission prompt is generated at the moment of the call, from the text of the call. What the reviewer would need to know about entitlement — which credentials this agent should ever hold, which repositories are ours, whether this tool's definition changed yesterday, what the last identical-looking request actually did — is not in the artifact. The reviewer supplies it from memory or not at all. Then the decision is consumed and discarded, and the next prompt arrives with the same missing context.

Anthropic's own documentation contains a remarkably candid statement of this. Boundaries a user states in conversation — "don't push", "wait until I review before deploying" — are treated as block signals by the classifier. But, the docs note, they "are not stored as rules. The classifier re-reads them from the transcript on each check, so a boundary can be lost if context compaction removes the message that stated it. For a hard guarantee, add a deny rule instead."

That is the argument in two sentences, written by the vendor. A stated boundary is an event in a transcript, and events decay. A rule is a state, and state is checkable.

The engineering post makes the same point from the other direction. On entering auto mode, Claude Code deliberately drops any pre-existing permission rule granting arbitrary code execution — blanket shell access, wildcarded interpreters, package-manager run commands — because leaving them active "would mean the classifier never sees the commands most capable of causing damage." Those rules are broad grants users set up for convenience. They are durable state, and a grant made months ago silently determines what gets reviewed today.

So the design conclusion follows. If oversight is going to hold, the durable object cannot be the click. It has to be a grant with a subject, a scope and a record: which identity, against which tool, under which rule, evidenced afterwards. The context a reviewer cannot hold in their head belongs in the system that renders the decision.

This is a different problem from approval volume. Approval fatigue is a real and separate failure, and fixing what triggers a prompt reduces how many decisions a person faces. It does not change what a single decision is made of. A team could cut its prompt count by ninety per cent and still be approving npm run analyze.

How Waxell handles this

The Waxell MCP Gateway treats the approval as a governed object rather than a modal dialog. It is one MCP endpoint per tenant that agent clients point at in place of their upstream configs, and the calls routed through it are evaluated before the upstream sees them and again on the way back. Three properties address the gap above.

The decision is attached to an identity, not a session. Under on-behalf-of OAuth, each tool call the gateway brokers is resolved to a real user, so when the call lands at GitHub or Slack the upstream's own log names the person who triggered it; a tenant that opts for the shared-service-account mode instead trades that attribution for speed of deployment. The approval has a subject that outlives the transcript it was granted in.

The approval outlives the process that collected it. When a policy rule requires review, the gateway parks the call and holds the MCP connection open with progress notifications so the agent does not time out; approving resumes the call upstream and the result returns normally, while denying returns a structured error the agent can recover from. Approvals, policy rules and OAuth grants live in the controlplane rather than in the gateway process, which is why an approval survives a gateway restart and stays consistent across instances. The approval pauses the agent; it does not break it.

The evidence is produced at decision time. Each brokered call is written to the audit log with the resolved identity, the decision that applied and the rules that fired — durable, exportable, no payload bodies retained. That answers the question the game data raises: not "did someone approve this", but "what was that person actually authorizing".

Underneath, the policy layer can allow a call, deny it, redact the result, or hold it for review, and rule changes reach the fleet within about 30 seconds without a restart. Newly discovered tools on a connected upstream sit at Pending review and, per the gateway's own status table, cannot be called until an admin approves them.

One boundary worth stating plainly, because the argument above cuts both ways: a gateway governs the calls that traverse it. An agent holding a direct upstream credential, a locally registered MCP server or an unconfigured client sits outside that path. Coverage is configured, not automatic — and a governance layer that quietly assumes otherwise is making the same mistake as a prompt that assumes the reviewer knows what npm run analyze does.

FAQ

Why do human approvers miss AI agent threats?

Because approval prompts render the syntax of an action rather than its consequence. Across 409,000 approve/deny decisions, reviewers missed obviously destructive commands 11.7 per cent of the time and credential-scope violations 35 per cent of the time. The commands that look alarming get caught; the ones that quietly move data do not. Legibility and blast radius are different properties, and only the first is on screen.

Does replacing the human reviewer with a model fix it?

It changes the tradeoff without closing the gap. Anthropic reports a 17 per cent false-negative rate for its Claude Code classifier on a curated set of 52 real overeager actions, and describes the dominant failure as the classifier finding approval-shaped evidence without checking whether it covers the action's blast radius — the same error mode as the human. Anthropic's own guidance is that auto mode is not a replacement for careful review on high-stakes infrastructure.

What is the difference between an approval and an authorization?

An approval is an event: a decision made at one moment, from the information visible at that moment, then consumed. An authorization is a state: a grant tied to an identity and a scope that persists and can be checked, revoked and evidenced later. Many agent permission systems collect the first and are later asked, usually by an auditor, to produce the second.

Is this the same problem as approval fatigue?

No, though they compound. Approval fatigue is about volume — too many decisions degrade the attention paid to each. This is about composition: a single decision, made carefully, can still be wrong because the artifact carries no scope. Cutting prompt count helps the first problem and leaves the second untouched.

Where does this leave human-in-the-loop as a control?

Intact, but re-scoped. Human judgement is valuable where a policy cannot resolve the question and wasted where one can. The design job is to make the system carry the checkable part — identity, entitlement, tool provenance, a durable record — so the decisions reaching a person are the ones that need a person, arriving with the context that makes them decidable.

Does routing tool calls through a gateway cover every agent action?

No. A gateway governs the calls that pass through it. Agents holding direct upstream credentials, locally registered MCP servers and unconfigured clients bypass that path, so coverage is a function of how the fleet is configured. Any team relying on a chokepoint should be able to say which of its agents actually route through it.

Sources


Originally published on the Waxell blog.

Your agents are already calling tools, and somewhere a person is clicking approve on a command they cannot fully read. Start free with the Waxell MCP Gateway at waxell.dev/signup — the Free plan includes one governed MCP upstream and 10,000 traced executions a month, and each call it brokers arrives with an identity attached and leaves a record behind.

Top comments (0)