ROOTVIELROOTVIEL
← Knowledge Base

Agentic architecture

Verified by ROOTVIEL11 min

Privilege Escalation Through Agents

An agent ends up exercising authority it was never granted. Comparing three views of its power — what it effectively has, what it actually uses, and what was declared to it — exposes the gap: authority in use or in reach that no grant ever authorized.

Classification

Domain
Agentic architecture
ROOTVIEL support
Verified by ROOTVIEL — A deterministic, LLM-free verifier settles a specific property under stated assumptions — either a structural property over a graph, or an effect reproduced in execution. It does not by itself mean the whole system is secure, nor that an end-to-end exploit was run beyond what the evidence scope states.
Evidence scope
Structural property — Checked over a static authority/dataflow graph — the property holds in the code; no exploit was run.
Analysis family
FAM-GENAI-STATIC
CWE
CWE-269, CWE-272
OWASP
LLM06

Definition

Privilege escalation through agents is an agent acquiring or exercising authority beyond what it was granted. The clean way to reason about it is the authority triad: the effective authority (everything the agent can reach, given its tokens, tools, and network position), the used authority (what it actually exercises in practice), and the declared authority (what a grant explicitly authorized it to have). Escalation is a mismatch among these — power effectively held or actually used that was never declared.

The triad turns a fuzzy question ("is this agent over-privileged?") into set arithmetic. Each view is a set of capabilities. Comparing them with set differences localises the problem precisely: effective-minus-declared is latent over-provisioning; used-minus-declared is active escalation — authority being exercised with no grant behind it.

Context

Agents acquire authority from many places — assigned tools, inherited credentials, network reachability, capabilities picked up through delegation. Over time the effective set drifts above the declared set, and some of that surplus gets used. Any agent whose granted authority is written down and whose effective/used authority can be observed is a candidate for triad analysis.

  • ▸An agent granted a narrow role but wired to tools that reach far beyond it.
  • ▸An agent that inherits a broad credential and exercises operations no grant covers.
  • ▸A sub-agent that accumulated capability through delegation and now uses more than was declared.

Technical fundamentals

Represent each agent’s authority as a set of capabilities drawn from an authority graph that records which tools, credentials, and resources each node can reach. The three views are three sets over that graph: declared (explicit grants), effective (transitive reachability), and used (observed exercise). The triad is then pure set algebra — effective ∖ declared and used ∖ declared — with FAIL reserved for the case that is unambiguous: authority present where no declared grant explains it.

This is deterministic and needs no probabilistic judgement, but it is only meaningful when the graph is populated with real data: real grants, real reachability, real usage. An empty or partial graph cannot distinguish "no escalation" from "no data", so the honest verdict on an unpopulated graph is UNKNOWN, not a pass. The analysis fails closed on absence of evidence rather than defaulting to "secure".

Effective authority
Everything the agent can reach — the transitive closure of its tools, credentials, and network position over the authority graph.
Used authority
The authority the agent actually exercises, observed from its behaviour.
Declared authority
The authority an explicit grant authorized; the only set a FAIL is raised against.

Root cause

The defect is a gap between declared grants and the authority an agent effectively holds or actually uses — over-provisioning that is never reconciled against what was authorized. Authority is handed out by wiring (a tool connected, a credential inherited, a path left reachable) rather than by explicit grant, so the effective set outgrows the declared set, and usage follows the surplus. Without a reconciliation that treats the declared set as the ceiling, the excess is invisible.

How the attack works, step by step

  1. 1An agent is declared a narrow set of authority for its role.
  2. 2Through wiring, inheritance, or delegation, its effective authority grows beyond the declared set.
  3. 3An attacker (or the agent’s own drifting behaviour) steers it toward the surplus capability.
  4. 4The agent exercises authority in the used-minus-declared gap — an operation with no grant behind it.
  5. 5The escalated action succeeds because the environment enforced wiring, not the declared grant.

Vulnerable example

A synthetic, illustrative setup where the agent is wired to far more authority than it was declared, and nothing reconciles usage against the grant:

synthetic — do not use; illustrates the flaw
# UNSAFE: effective authority far exceeds declared; usage never reconciled. declared = {"read:tickets"} # the grant agent = Agent(tools=[read_tickets, delete_users, deploy_prod]) # effective >> declared def act(agent, op): return agent.invoke(op) # no check against 'declared' act(agent, "delete_users") # used \ declared -> escalation, unflagged

Corrected example

Reconcile against the declared grant as the ceiling. Compute the triad over a populated authority graph, FAIL on any used capability outside the declared set, and enforce the declared set at invocation so the effective surplus is never exercisable in the first place.

synthetic — triad reconciliation + declared-set enforcement
# SAFER: declared grant is the ceiling; triad computed on real data. def triad(agent, graph): if not graph.populated(agent): return "UNKNOWN", None # no data != no escalation declared = graph.declared(agent) effective = graph.effective(agent) # transitive reachability used = graph.used(agent) # observed exercise over_provisioned = effective - declared # latent risk escalated = used - declared # FAIL condition if escalated: return "FAIL", {"escalated": escalated, "latent": over_provisioned} return "OK", {"latent": over_provisioned} def act(agent, op): if op not in graph.declared(agent): # enforce the ceiling at the call raise Denied("operation outside declared authority") return agent.invoke(op)
Note

Limit of the fix: the FAIL is raised only against the declared grant and only when the graph is populated. Effective-minus-declared is surfaced as latent over-provisioning, not a FAIL — it is a signal to tighten wiring, not proof of harm. With no real grant/usage data the only honest output is UNKNOWN.

Impact

  • ▸Authorization: the agent performs operations no grant authorized, defeating least privilege.
  • ▸Integrity: escalated actions (deletions, deployments, config changes) alter systems outside the agent’s intended role.
  • ▸Blast radius: a compromised agent with surplus authority can reach far beyond the task it was meant for.
  • ▸Auditability: usage that no grant explains undermines the ability to reason about what the agent is allowed to do.

Detection

Compute the authority triad over a populated authority graph and take the set differences. A FAIL is raised only on used-minus-declared — authority actually exercised with no declared grant behind it — which is the unambiguous escalation signal. Effective-minus-declared is reported as latent over-provisioning. Crucially, the analysis is gated on a populated graph: without real grant and usage data it returns UNKNOWN, never a pass, because absence of data is not absence of escalation.

How ROOTVIEL analyzes it

Support level
Verified — the execution engine computes the authority triad as pure set diffs over the authority graph.
Family
FAM-GENAI-STATIC — static graph/set reasoning.
The triad
effective (reachable), used (exercised), and declared (granted) authority, compared by set difference.

The engine derives the three authority sets from the authority graph and compares them: effective ∖ declared flags latent over-provisioning, and used ∖ declared is the escalation condition. A FAIL is raised only against a declared grant — only when an exercised capability has no grant behind it.

Verified

Honest framing: the triad is pure set arithmetic, but it is gated on a populated graph. Without real grant and usage data the verdict is UNKNOWN, never "secure" — absence of data is not absence of escalation. FAIL is reserved for used-minus-declared; effective-minus-declared is surfaced as latent over-provisioning, a signal to tighten, not a confirmed exploit.

Mitigation

Treat the declared grant as the ceiling and reconcile the other two views against it continuously.

  • ▸Preventive: grant least-privilege authority explicitly and enforce the declared set at invocation so the effective surplus is never exercisable.
  • ▸Preventive (wiring): wire agents only to the tools, credentials, and network paths their declared role needs, shrinking effective-minus-declared toward empty.
  • ▸Detective: compute the triad over a populated authority graph in CI and at runtime; alert on any used-minus-declared FAIL and track latent over-provisioning.
  • ▸Corrective: revoke surplus authority, fail closed on an escalation attempt, and keep usage logs that let the triad be recomputed from real data.

Verifying the mitigation

Verify by populating the authority graph with real grant, reachability, and usage data and confirming used-minus-declared is empty (no FAIL) while latent over-provisioning is tracked and shrinking. Attempt an operation outside the declared set and confirm invocation-time enforcement denies it. Run the triad against an unpopulated graph and confirm it returns UNKNOWN rather than a pass. Report as "no used-minus-declared escalation over the populated graph".

Note

The decisive honesty check is the UNKNOWN path: if the graph is not populated with real data, the triad must not report OK. Treating UNKNOWN as a pass silently reintroduces the vulnerability.

Common mistakes

  • ▸Wiring an agent to broad tools/credentials and relying on it to only use the narrow part.
  • ▸Reading an empty triad result as "no escalation" when it actually means "no data" (UNKNOWN).
  • ▸FAILing on effective-minus-declared and crying wolf, instead of reserving FAIL for used-minus-declared.
  • ▸Granting authority implicitly through wiring and never reconciling it against an explicit declared ceiling.

References

  1. [1]OWASP Top 10 for LLM Applications — LLM06 Excessive Agency
  2. [2]OWASP Agentic Security Initiative
  3. [3]MITRE ATLAS
  4. [4]MITRE CWE-269 (Improper Privilege Management), CWE-272 (Least Privilege Violation)
  5. [5]Model Context Protocol — Specification

References point to public, well-known technical sources for further study.

Related articles