Treat an agent approval as a security control only when the person sees the exact material effect and the server executes that same effect once. Put approval immediately before the irreversible boundary, show the real target and consequences in human terms, bind the decision to canonical action data and current resource versions, expire it quickly, and have trusted server code consume it atomically. A generic “Allow agent to continue?” dialog does not establish meaningful, parameter-specific approval and should not be treated as proof of legal consent.
OWASP recommends human approval for high-impact agent actions and warns about approval manipulation and excessive autonomy (OWASP AI Agent Security Cheat Sheet). Its transaction-authorization guidance adds two essential properties: authorization should be specific to the transaction data and enforced as a server-controlled sequence, with defenses against modification and replay (OWASP Transaction Authorization Cheat Sheet).
Define the boundary before designing the dialog
Do not begin by placing approval modals after arbitrary tool calls. Inventory agent operations and classify their effects:
| Tier | Examples | Default interaction |
|---|---|---|
| Observe | Read a permitted record, search approved documentation | No per-action approval; visible activity and access policy |
| Prepare | Draft an email, construct a patch, preview an order | No commit authority; make the preview inspectable |
| Reversible commit | Create a draft ticket, schedule a reversible job | Clear confirmation when impact is meaningful; offer undo |
| High impact | Send externally, publish, pay, delete, change access, deploy | Transaction-specific approval at the commit boundary |
| Exceptional | Large transfer, production-wide change, secret export | Strong reauthentication, separation of duties, or independent approver |
These are design recommendations, not universal regulatory categories. Set thresholds from your threat model, organizational policy, user population, and the reversibility and blast radius of each action.
The model must not decide that its own action is low risk. A deterministic policy service should classify the typed operation and evaluated arguments. It should also deny actions outside the user's authority before asking for approval; a confirmation cannot grant a privilege the approver does not possess.
Split preparation from commitment
Use two different tool capabilities:
prepare_payment(invoice_id)
-> preview { recipient, verified account, amount, currency, source, fees }
commit_payment(preparation_id, approval_token)
-> effect receipt { provider_reference, committed_at, final status }
The preparation step performs validation and produces a server-owned record. The agent can explain the proposed action but cannot alter the authoritative preview. The commit endpoint accepts a reference to that record, not a fresh model-generated copy of the amount or recipient.
This structure also improves ordinary workflows: a user can inspect a message in its final rendering, view a deployment plan, or see the exact files to delete before any external effect occurs.
Show the facts that could change the decision
The confirmation surface should answer:
- What exactly will happen?
- Who or what is the target?
- Which account, tenant, workspace, and environment are involved?
- What value, scope, or number of records is affected?
- Is the action public, external, billable, privileged, or irreversible?
- When will it happen, and is there an undo window?
- Why is the agent proposing it, and which user request led here?
For a payment, emphasize recipient, amount, currency, funding source, fees, and schedule. For an email, show recipients—including BCC—subject, attachments, and final body. For a deployment, show service, environment, artifact digest, configuration changes, and rollback plan. For deletion, show the resource names and count rather than only an internal batch identifier.
Render important values from trusted structured data. Do not let the model supply the warning text, hide details in generated prose, or choose the visual hierarchy. Untrusted document text must not be able to resemble a system confirmation.
Offer meaningful choices: cancel, go back and edit, inspect details, and approve. Avoid preselected approval, confusing double negatives, artificial urgency, or a primary button labeled only “Continue.” The user should know the action without reconstructing it from conversation history.
Cryptographically bind approval to the preview
At preparation time, serialize a canonical action object using a documented, deterministic format and compute a digest. Store the full object server-side:
{
"operation": "send_email",
"actor_id": "user_123",
"tenant_id": "tenant_45",
"recipients": ["customer@domain.invalid"],
"subject": "Final renewal terms",
"body_digest": "sha256:...",
"attachment_digests": ["sha256:..."],
"resource_versions": {"draft": "17"},
"expires_at": "...",
"nonce": "..."
}
The approval record should bind at least:
- approver identity and authenticated session;
- tenant and active role;
- operation and all material parameters;
- a preparation identifier and action digest;
- resource versions or preconditions;
- policy version and required assurance level;
- issue and expiry time; and
- a unique nonce and unused status.
The example domain is intentionally non-resolving; the structure is illustrative, and the digest is not a substitute for storing the exact approved data.
At commit, trusted code loads the preparation, verifies identity and current authorization, checks the digest and expiry, confirms resource versions, marks the approval consumed, and performs the effect in one transaction or idempotent workflow. If the draft, recipient, amount, permissions, or policy changed, invalidate the approval and show a new preview.
Signing a token can prevent client-side alteration, but it does not solve stale authorization, changed resources, or replay by itself. Keep a server-side consumption record and an idempotency key. A retry should return the original receipt rather than execute the action again.
Close the time-of-check/time-of-use gap
Many unsafe approval flows validate a preview, then reconstruct the action from mutable state. Between those moments, an agent, another user, or an integration changes the target.
Use one or more of these patterns:
- immutable prepared objects;
- optimistic concurrency with resource versions;
- database transactions for consume-and-commit;
- downstream idempotency keys;
- a short reservation on inventory or other changing resources; and
- re-preview when a consequential dependency changes.
Do not hold a database transaction open while a human considers a dialog. Prepare durable state, then validate its preconditions again during the short commit transaction.
Require stronger evidence for exceptional actions
For the highest-risk operations, an existing web session may be insufficient. Require recent reauthentication, a phishing-resistant authenticator where appropriate, an independent approver, or an out-of-band channel that displays the same transaction facts. The goal is not extra clicks; it is independent evidence that the authorized person consented to this effect.
Do not send only “Approve request 5821” to the second channel. Display the material recipient, amount, environment, or permission change so malware cannot substitute the action while preserving the reference number.
Administrative “approve all” and standing-consent features need strict scope, expiry, revocation, and visibility. They should not silently convert a high-impact tier into unsupervised autonomy.
Design against fatigue and inaccessibility
If every read generates a modal, users will approve reflexively. Reserve interruptive confirmation for material effects, group only actions whose full scope remains understandable, and make safe defaults easy. Use previews, dry runs, delayed execution, undo, and policy-based limits to reduce both risk and prompt volume.
Approval must be operable by keyboard, expose programmatic names and state, preserve focus, announce errors, and not rely only on color. WCAG 2.2 is the current W3C accessibility recommendation and provides testable criteria for perceivable and operable interfaces (W3C Web Content Accessibility Guidelines 2.2). Test the exact flow with screen readers, zoom, high contrast, mobile viewports, and reduced motion rather than assuming a component library makes it accessible.
For long-running agents, provide a persistent activity view and a global stop control. Cancel pending preparations when the task is revoked. Explain whether stopping prevents future actions, attempts to cancel in-flight work, or cannot reverse completed effects.
Record evidence without leaking sensitive data
Log the preparation identifier, action digest, policy decision, approver, authentication assurance, displayed preview version, decision, timestamp, commit result, idempotency key, and effect receipt. Do not log raw secrets, full payment credentials, or sensitive message bodies merely to prove approval. Store protected content under appropriate retention and access controls, with hashes and durable references in the audit event.
The final receipt should tell the user what happened and provide a path to inspect, undo, dispute, or escalate. “Done” is not adequate for a consequential action.
Test the complete sequence
Automate at least these cases:
- modify each material field after preview and expect reapproval;
- reuse an approval token and expect no second effect;
- commit after expiry, logout, role removal, or tenant switch;
- race two commit requests and verify exactly one effect;
- change a resource version between preparation and commit;
- fail downstream after approval and surface an unambiguous state;
- retry an indeterminate downstream response with the same idempotency key;
- inject misleading text into model output and source documents;
- navigate and decide entirely with keyboard and assistive technology; and
- stop the agent with pending and in-flight actions.
Test the server invariant and downstream receipt, not whether the model says it asked permission.
Production checklist
- Classify operations by effect using deterministic policy outside the model.
- Separate preview-only tools from commit capabilities.
- Render exact material facts from trusted structured data.
- Bind approval to actor, tenant, operation, parameters, versions, policy, expiry, and nonce.
- Recheck authorization and preconditions at commit.
- Consume approval once and make downstream retries idempotent.
- Require stronger authentication or a second person for exceptional impact.
- Keep cancel, inspect, edit, undo, and stop controls clear and accessible.
- Minimize prompts so approval remains meaningful.
- Record the decision and effect receipt without logging secrets.
- Invalidate approval after any material change.