The AI Learning Hub Journal
◆ Controls

Least Privilege for Agents

Design the toolset the way you would design a rolestart from the task and work forward — every registered tool is a granted permissionHOW PRIVILEGE ACCUMULATES· everything the server exposes gets registered· one service identity reused across the feature· standing credentials that never expire· arbitrary-query tools invite argument steering· nobody owns removal — the list only growsDESIGNED AS A PERMISSION SET· start from the task and work forward· purpose-built, typed, narrow tools — read split from write· one credential per tool, exactly its operations· short-lived, per-run credentials — expiry is a control· a scheduled review owns removalCARRY THE REQUESTING USER'S AUTHORITY ON EVERY USER-DATA READthis agent, acting for this user — a shared service identity for retrieval is the standard route to cross-user disclosureverify by attempting access as the agent, not by reading the role definitionWHERE UNTRUSTED CONTENT MEETS PRIVILEGE — SPLIT BY TRUST, NOT CONVENIENCEuntrustedexternal contentREADERno credentials · no private datano egress — emits typed fieldsTYPED INTERFACEconstrained, validatedfields onlyPRIVILEGED ACTORholds the credentials —never sees raw prosea free-text summary across the interface re-opens exactly the channel the split removedTHE BOUNDARY HOLDS BECAUSE THE INTERFACE ENFORCES IT, NOT THE MODELthe same reasoning that separates a parser from an executor in any security-sensitive design
Give the agent a role, not an inheritance: task-forward tools, per-tool short-lived credentials, and a typed interface between reader and actor.

Design the Toolset as a Permission Set

The most effective control available is also the least glamorous: give the agent fewer capabilities. Every tool registered is a permission granted, so design the toolset the way you would design a role. Start from the task and work forward — what does this feature actually need to do — rather than starting from an available server and registering everything it exposes. Prefer narrow, purpose-built tools over general ones: a tool that fetches a customer's open tickets is safer than one that accepts an arbitrary query, because the narrow tool cannot be steered into returning something else. Split read from write, so a feature that mostly reads holds a read-only tool set and a write path exists only in the step that needs it. And review the list on a schedule, because tool lists grow monotonically unless someone is responsible for removing what is no longer used.

  • Each registered tool is a granted permission — design the list, do not accumulate it
  • Purpose-built tools resist argument steering that arbitrary-query tools invite
  • Separate read tools from write tools and expose write only where needed
  • Tool lists grow unless someone owns removal; schedule the review
  • On the standard maps: OWASP's LLM Top 10 frames this risk as excessive agency — least privilege is its first-line mitigation

Credentials: Scope, Delegation, and Lifetime

Behind every tool is a credential, and that is where excessive privilege usually hides. Three properties matter. Scope: the credential should permit exactly the operations of the tool it backs, which means separate credentials per tool rather than one service identity reused across a whole feature. Delegation: for anything that reads user-specific data, the call must carry the requesting user's authority so the system cannot return data the user could not otherwise reach — using a broad service identity for retrieval is the standard route to cross-user disclosure, and it is convenient enough that it appears in most systems that have not been reviewed. Lifetime: prefer short-lived, task-scoped credentials issued per run over standing ones, so that a compromised or hijacked run has a bounded window. Expiry is a control, not an operational inconvenience.

  • One credential per tool, scoped to that tool's operations
  • Carry the requesting user's authority on any user-data access — never a shared service identity
  • Issue short-lived per-run credentials so hijacking has a bounded window
  • Audit resolved effective permissions, not role names

Split by Trust, Not by Convenience

Where a feature genuinely needs both untrusted content and privileged access, the durable answer is to split it into components with different trust levels rather than to defend the combination. A retrieval or browsing component runs with no credentials, no private data, and no egress, and its job is to reduce external material into structured, validated fields. A privileged component consumes those fields and never sees raw external prose. The interface between them carries typed data with constrained values, which is what makes the boundary meaningful — passing a free-text summary across the boundary reintroduces exactly the channel the split was meant to remove. This is the same reasoning that separates a parser from an executor in any security-sensitive design, and it holds here because the constraint is enforced by the interface rather than by the model's good behaviour.

  • Unprivileged reader, privileged actor, typed interface between them
  • The reader gets no credentials, no private data, and no egress
  • Pass constrained typed fields — a free-text summary re-opens the channel
  • The boundary works because the interface enforces it, not because the model respects it

Prefer slides, quizzes, and saved progress? Read this lesson in the library — free, no sign-up.