---
title: "0001 Agent Is A Ui Not A Trust Boundary"
description: ""
---

# 0001 — The agent is a UI, not a trust boundary

## Status

Accepted.

## Context

We are adding an AI chat/agent to a React SPA backed by AWS APIs (Cognito for
auth). The agent can propose backend API calls; the user approves each one;
the browser executes the approved call using the user's existing access token.
The LLM never sees the token.

A natural question: should the chat backend independently re-validate every
proposed call against the user's permissions before sending it to the
browser? Should the allowlist enforce per-call authorization server-side?
Should we treat the agent's outputs with a privilege model distinct from the
user's own?

## Decision

No. The agent is treated as **a different UI on top of the same APIs**, not
as a privileged actor. The backend APIs remain the sole authorization
boundary, exactly as they are for the existing SPA. The user's access token,
issued by Cognito, is the user's identity for every call regardless of
whether the call originated from a click or from an agent-emitted
[[Tool-Call Proposal]] the user approved.

Concretely: anything the user can already do via the existing UI, the agent
can propose. Anything the user can't do via the existing UI, the API will
reject — and that rejection is the only authorization check we rely on.

## Consequences

- **The agent adds no new backdoors.** It cannot do anything the user
  couldn't already do by clicking. Per-call HITL approval is defense in
  depth against the user being *tricked* into approving something they could
  legitimately do but shouldn't (e.g., prompt-injected tool results), not
  against privilege escalation.
- **No server-side re-validation of proposals.** The chat backend forwards
  what the model emitted; the browser asks the user; the API enforces.
- **API authorization quality is load-bearing.** If an endpoint trusts an
  ID in the request body without re-deriving ownership from the token, that
  is a pre-existing IDOR — but the agent makes it dramatically easier to
  exploit because the LLM can be coaxed into substituting IDs the user
  wouldn't think to type. We assume backend APIs are doing authn/authz
  correctly today, and treat any failure of that assumption as a backend
  bug, not an agent bug.
- **Allowlist scope is a UX decision, not a security one.** We may still
  curate which operations are exposed (to keep the model focused, reduce
  catalog size, suppress nonsensical-in-chat operations), but the curation
  is not protecting the backend. Removing something from the allowlist
  means the agent won't propose it, not that the user couldn't still
  perform it through the regular UI.
- **Token scope and overprovisioned permissions matter more, not less.** If
  the user's token grants ability to call admin endpoints that the existing
  UI hides, the agent will happily find and surface those endpoints. Token
  scopes should reflect what the user *should* be able to do, not what
  any user can do.

## Alternatives considered

- **Server-side re-validation of every proposal against a user
  permissions store.** Rejected: duplicates the API's own authorization
  checks (which is the canonical source of truth) and can drift from
  them, producing a *worse* security posture than relying on the API.
- **A separate, narrower set of "agent-allowed" actions distinct from
  what the user can do in the UI.** Rejected: complicates the mental
  model, requires a parallel permissions system, and breaks the
  "the agent is just a different UI" framing.