Layer 01
Held is not the same as used.
An agent usually holds more access than its task uses, because nobody can list in advance what an agent will need. The access it never uses is not idle. It is available to anyone who can steer the agent.
The Problem
Why agent permissions are rarely scoped.
It is not carelessness. The permission set an agent needs cannot be known when it is built.
01
Agents choose their tools while they run
A normal service calls the same endpoints every time, so it can be scoped in advance. An agent decides which tools to call based on what it reads, so there is no fixed list to scope against.
02
The cost of a mistake is lopsided
Grant too little and the agent fails in front of a user. Grant too much and nothing visible happens, until it does. Teams avoid the visible failure, so they over-grant.
03
Tools change faster than reviews
A new tool or MCP server can be added in an afternoon. Access reviews happen every quarter. In between, nobody re-scopes.
The Method
Learn what it needs. Enforce exactly that.
Observe first, derive second, and enforce only after a person has approved the result.
01
Learn
In learn mode the gateway forwards everything and records which capabilities each task actually uses, by default over 14 days.
02
Derive
A capability enters the draft policy only if it appears often enough and in enough separate sessions. One unusual session cannot add a permission.
03
Approve
A named person reviews the draft and the exposure report, which shows held versus used for each agent. Nothing is enforced until they mark it approved.
04
Shadow, then enforce
Shadow mode shows what would be blocked without blocking it. Enforce mode blocks what is outside the policy and pauses the rest for a person.
Example policy (illustrative values)
task_class: invoice_reconciliation
approved: true # set by a person, never by the learner
k: 5 # minimum separate sessions per capability
capabilities:
- selector: ledger.invoices.read
support: 0.92
distinct_sessions: 41
max_benign_taint: 1
- selector: ledger.payments.read
support: 0.88
distinct_sessions: 37
max_benign_taint: 1
# mail.send.external was never observed, so it is not in the policy
Poisoning Resistance
A learner can be taught the wrong thing.
If an attacker can make an agent behave badly during the learning window, a naive learner would write that behaviour into policy. Three defences stop that.
01
Count sessions, not calls
Support is counted over distinct sessions. One poisoned run that repeats a capability a thousand times still counts once.
02
Weigh by provenance
Behaviour first seen after the agent read untrusted content counts for less.
03
Trim the outliers
Sessions with unusually high call volume are set aside before support is counted, so a few busy sessions cannot dominate.
Questions
Least privilege, in practice.
Each agent can use only the tools and data its task actually needs, and that is checked on every call, not only when access is granted.
The default learning window is 14 days in learn mode. Agents with irregular work can learn for longer. Nothing is blocked while it learns.
An out-of-policy call is never dropped silently. It is paused for a person, who can allow it once, add it to the policy, or deny it.
Each capability counts once per session, behaviour seen after the agent read untrusted content counts for less, and unusually busy sessions are discarded. A person still approves every policy.
Find out what your agents
are actually allowed to do.
Early access starts with a two-week shadow-mode pilot. Nothing is blocked. You get the gap between the access each agent holds and the access it uses, and every combination that could move data out.