# A Confirm Button Is Not a Coding-Agent Security Boundary

> Source: <https://dev.to/hefty_69a4c2d631c9dd70724/a-confirm-button-is-not-a-coding-agent-security-boundary-5700>
> Published: 2026-08-26 07:13:33+00:00

A coding agent asks for permission to modify `packages/web/generated/client.ts`

. The path looks harmless, the proposed diff sounds reasonable, and the user clicks Approve.

That approval means very little if the system has not resolved where the write will land. A symlink or another layer of indirection can make the effective destination different from the path in the dialog. The human reviewed one operation while the machine executed another.

A confirm button becomes a security boundary only when approval and execution refer to the same action. The action executed must be the action reviewed.

This is narrower than the usual "keep a human in the loop" advice. A human can be present, attentive, and still approve the wrong thing because the interface showed a story about the action instead of the computed action itself.

There are three separate objects in an agent workflow:

Teams often collapse them into one approval prompt. That works until a path resolves somewhere unexpected, a skill changes between review and execution, or a broad session permission gets reused for a materially different tool call.

The model's narration is useful context. It is not the authorization object. Models summarize, omit details, and can be wrong. The runtime already knows more precise facts: the effective resource, operation, credentials, network access, loaded tool code, and environment that will receive the action.

Approval should bind to those facts. If any material fact changes, the old approval is invalid. The system should prepare a new proposal and ask again.

That rule also cuts through a lot of fuzzy permission design. "Allow file edits for this session" is easy to implement and difficult to reason about. "Allow this write to this resolved path, using this tool version, before this expiry" is much less convenient. It is also something a reviewer can understand.

A practical approval envelope can stay small. It needs enough information to identify the proposed effect without pretending to be a universal protocol.

```
proposal_id: apv_7f31
requested_resource: packages/web/generated/client.ts
resolved_resource: /workspace/task-184/packages/web/generated/client.ts
operation: write
capabilities:
  - filesystem:write:/workspace/task-184/packages/web/generated/client.ts
skill:
  name: api-client-generator
  version: 2.4.1
expires_at: 2026-08-26T06:15:00+08:00
expected_evidence:
  - changed-paths
  - diff
  - test:generated-client
```

The exact fields will vary. A database migration needs a target database and transaction policy. A deployment needs an environment, artifact identity, and rollback path. A browser action may need an account, origin, and allowed side effect.

The sequence matters more than the exact field names:

A proposal hash can help detect mutation, but a hash does not prove that the underlying operation is safe. It only proves that the bytes did not change. The user still needs a readable view of the facts being authorized, and the runtime still needs to enforce them.

Natural-language intent does not fully identify an agent operation. The same request can behave differently depending on the tool, plugin, MCP server, or reusable skill loaded into the run.

That matters because agent skills have become a software supply-chain surface. Security reporting has described typosquatted skills that instructed agents to fetch credential-stealing code. The broad lesson is not that every shared skill is malicious. It is that "generate the API client" does not describe the full action when an external instruction package decides which commands to run.

Bind the relevant identity into the proposal:

Installation trust and run-time authority are different decisions. A team may allow a reviewed skill to exist in its environment without allowing every invocation to access credentials or the network. The reverse is also true: approving a task does not make a newly substituted dependency trustworthy.

If the skill revision changes after approval, the proposal changed. Ask again. Quietly preserving consent across a tool update defeats the point of naming the tool in the first place.

Parallel coding-agent products increasingly give each task an isolated worktree, terminal, conversation, and review state. That is a sensible operating model. Vendor tooling is also moving toward persistent isolated environments and resumable agent state.

Isolation limits the blast radius. It does not prove that the action inside the boundary matches what the human approved.

An agent can execute the wrong command in the correct sandbox. It can write to an unexpected resolved path that still exists inside the worktree. It can use an untrusted skill with tightly scoped permissions. Containment may turn a severe failure into a recoverable one, which is worth doing, but approval integrity is a separate property.

Treat the two controls as complementary:

A worktree is useful for filesystem isolation and review. A sandbox can restrict process, network, and credential access. Neither should be presented as proof that the reviewer saw the exact operation that ran.

Most approval interfaces spend too much space on the model's prose. "I will safely update the generated client and run the relevant tests" sounds reassuring, but it is not specific enough to authorize anything.

Give the computed fields the visual priority:

```
Requested path: packages/web/generated/client.ts
Resolved path:  /workspace/task-184/packages/web/generated/client.ts
Operation:      write
Capabilities:   one-file write, test command
Skill:          api-client-generator@2.4.1
Expires:        06:15 CST
Evidence:       changed paths, diff, generated-client test
```

Show a warning when requested and resolved resources differ. Make capability expansion obvious. Put the tool or skill revision near the approval control instead of burying it in a log panel. If the system cannot compute a field, label it unknown rather than filling the gap with the model's confidence.

This interface problem is getting more relevant as agents render their own controls and task-specific surfaces. Builders comparing component catalogs, MCP UI tools, renderer patterns, and trusted-rendering approaches can use [Generative UI resources](https://awesomegenerativeui.com/resources) as one reference set. Whatever stack you choose, keep the authorization facts under host control; the agent should not get to invent the fields that authorize its own action.

Low-risk operations can still use broader policy approval. Formatting Markdown in a disposable branch does not need the same ceremony as rotating credentials or modifying a release workflow. The broader policy must still name its resource and capability bounds. "Do harmless things" is a preference, not an enforceable policy.

Approval records intent. A receipt records what happened.

At minimum, preserve the proposal identity, actual changed resources, tool calls, exit state, policy exceptions, and the evidence shown to the reviewer. For repository work, that often includes a diff and test output. It may also require checking effects that ordinary `git status`

does not reveal.

This is where path-resolution failures become visible. Suppose the approved proposal names one resolved destination, but the receipt shows another. The system should not call the run successful and tuck the mismatch into a warning. It should mark the transaction failed or require a new approval before continuing.

The same rule applies when execution discovers that it needs more authority. If a one-file edit now requires a package install and outbound network access, stop. Prepare another proposal. Do not stretch the first approval until it covers whatever the agent wants next.

Receipts also make review state durable. Parallel tasks can resume without relying on a conversational summary of what supposedly happened. A reviewer can inspect the approved operation, the actual effect, and any divergence between them. Current developer skepticism around coding agents often lands here: humans still have to reconstruct and review the accepted result. Better evidence does not eliminate that work, but it makes the work bounded.

The original dialog did not need a longer explanation. It needed a resolved destination, a bounded capability, a named skill revision, an expiry, and a promise about the evidence that would follow.

Once those facts were bound to one proposal, any material change should have invalidated the click. After execution, the receipt should have proved whether the runtime honored the proposal.

This model will not stop every prompt injection, dependency attack, credential leak, or runtime exploit. It does enforce one useful property that a plain confirm button cannot: the human approves an action the system can identify, constrain, and compare with the result.

Do not ask people to approve a sentence the agent wrote about itself. Ask them to approve the exact operation the runtime is prepared to enforce.
