← Blog · Approved, Not Shown

Research · consent surface · display–authorization binding

Approved. Not Shown.

Signing binds an artifact to its author. Attestation binds an agent to its authority. Nothing in the stack binds an approval to the screen the human read before granting it — and six findings this summer all walked through that gap.

Published 29.08.2026 · ~9 min · class: consent delta · status: new taxonomy

Three gates, and only two of them verify anything.

The agentic stack has converged on a defensible shape. An artifact arrives signed, so its origin is provable. An agent acts under attested capability, so its authority is traceable to a delegation chain. And where the action is dangerous enough, a human is put in front of it and asked to approve.

The first two gates have cryptography behind them. The third has a rectangle.

That asymmetry is not an oversight anyone chose. Signing and attestation operate on bytes, and bytes are easy to bind. Consent operates on a human's understanding, and no protocol in production today carries any statement about what that human was shown. The approval that comes back is a boolean. It records that a person clicked, not what the person read.

Which means the entire security value of the third gate rests on an assumption made nowhere explicit: that the rendered surface is a faithful projection of the action. Every finding below is that assumption failing, and in every case the input that drove the rendering was attacker-controlled.

Lay them side by side.

Injection sourceWhat the operator sawWhat actually ranMechanismTiming
Crafted deeplink Truncated install command Attacker MCP server, unsandboxed truncation attacker
Malicious repository In-workspace path Write outside the workspace substitution attacker
Repo settings file Trust dialog (later) Shell command on project open pre-emption attacker
Repo MCP config Nothing — gate removed All servers auto-approved pre-emption attacker
One-pixel page text Ordinary page content Agent rewrote its own config pre-emption attacker
Public issue body A bug report Private repo contents disclosed substitution attacker

Findings as summarised in the July–August 2026 coding-agent and agentic-security digests; the symlink pattern was reported independently twice before reproducing across six assistants.

The delta is a number, not an impression.

For each finding, ask one question: of the action that consent authorized, how much of it could the operator actually read on screen? That fraction is reportable, comparable across products, and testable in CI. Its complement is the delta.

TRUNC Deeplink MCP install — command clipped off-screen Δ 59%
SUBST Symlink write-outside-repo — path shown ≠ path written Δ 100%
PREMPT Hook on project open — ran before the dialog Δ 100%
PREMPT Config auto-approve override — consent gate disabled by repo Δ 100%
PREMPT Hidden text rewrites config — agent re-approved itself Δ 100%
SUBST Issue body as instruction — no approval surface at all Δ 100%

Five of six sit at Δ 100%. That is the finding underneath the finding: in almost every case the operator was not shown a partially misleading account of the action, they were shown nothing about it at all — while the system recorded, and downstream components trusted, a granted approval.

Three ways the gap opens.

01

Truncation — the string is longer than the box.

The full action is present in the approval payload and the operator authorizes all of it, but the surface renders only a prefix. Nothing is forged; the display simply ran out of room, and the remainder inherits consent it never asked for. This is the only mechanism where the delta is a continuous quantity rather than a binary one — and the only one a width constraint alone can close.

02

Substitution — the label and the referent disagree.

The operator reads a true statement about a thing that is not the thing acted upon. A symlinked path, a resolved alias, a rendered title standing in for a body. Every character on screen is accurate and the authorization still lands somewhere else, which is why input sanitisation and length limits both miss it entirely.

03

Pre-emption — the action outruns the dialog.

The most common of the three, and the least discussed. Execution begins before the approval surface exists, or the surface is disabled by the same artifact it was meant to gate. The delta here is total: not a mismatch between shown and authorized, but an authorization that was never solicited and is nonetheless treated downstream as though it had been given.

Why the other two gates cannot cover for this one.

HCAP answers a question about authority: did this agent hold the capability it exercised, and where did that authority come from? In four of the six findings the answer is an untroubled yes. The agent was permitted to write files, install servers, read repositories. Capability was never exceeded — it was invoked against a target the operator did not choose.

ABFP answers a question about behaviour: does what this agent is doing match what this agent normally does? That catches the tail of several of these, and catching the tail is worth real money. But a baseline deviation is evidence that something already happened, and an approval is precisely the artifact organisations point to when arguing that what happened was intended.

There is a third relationship neither one covers, because it is not a property of the agent at all. It is a property of the pair (what was displayed, what was authorized), and today nothing in MCP, A2A, or any agent framework emits a statement about the first element of that pair.

This is also the cleanest available reading of ASI09, Human-Agent Trust Exploitation. The category is often treated as social engineering of the operator. These findings are narrower and more tractable than that: the operator reasoned correctly about a surface that misrepresented the system.

What a scanner can and cannot see from outside.

Two mas-sentry-toolkit modules already probe the server half of this surface: the elicitation consent path, where a server suspends a call to ask a human for input, and the MCP Apps UI surface, where a server supplies content that a client will render. Both answer the question a remote scanner is entitled to answer — what did the server send toward the consent surface?

Neither answers the question this research is about. The delta lives between the payload and the pixels, and the pixels belong to the client. A scanner that never renders the dialog cannot measure how much of the command survived the box it was drawn into. Reporting otherwise would be exactly the failure mode the toolkit is built to avoid: a probe that establishes nothing being written up as a finding.

So the honest split is this. Server-side, the delta's ingredients are observable and worth flagging — an over-long command string, a display field that disagrees with the operative field, a server that declares a consent requirement and then behaves as though it were satisfied. Client-side, the delta itself is only measurable by something holding the render context. Today nothing does, which is why the third gate has no telemetry and no test suite.

The missing primitive: an attested render digest.

The fix has the same shape as the fix for every other unbound assertion in this stack. If an approval is going to be treated as evidence, it has to carry a statement about what produced it.

Concretely: when a client renders a consent surface, it hashes the surface as displayed — the visible text of the action, after truncation, after resolution of any path or alias, as the operator's eyes received it. That digest travels with the approval. Any component that later relies on the approval can compare the digest against the action it is about to perform, and refuse when they disagree.

This does not require the protocol to understand rendering. It requires one field and one commitment from the client: that the digest covers what was shown and not what was received. Truncation then becomes detectable rather than invisible, because the hash of a clipped string does not match the hash of a full one. Substitution becomes detectable, because the digest covers the resolved target. Pre-emption becomes detectable by absence — an action that arrives claiming approval with no digest attached never had a surface at all.

The obvious objection is that a compromised client can forge a digest, and that is true. It is also true of every attestation: the guarantee terminates at the trust boundary. What the digest buys is that the server, the audit log, and any downstream agent stop having to take an unqualified boolean on faith — which is a materially better position than the one every deployment is in today.