Skip the definition. Everyone agrees least privilege is correct in principle and almost nobody implements it for AI coding agents in practice, because the agent's whole appeal is that you can throw any task at it. So you hand it a credential broad enough for anything, and least privilege quietly dies the day the agent ships. The operational question is how to give an agent enough access to be useful without that credential being the keys to production.
This is the practical take, not the theory. Least privilege for an agent is an access-provisioning problem, and the default way teams provision agent access is the opposite of least privilege.
Why the default goes wrong
The agent gets a long-lived service credential at setup, scoped wide so it does not get blocked mid-task. From then on:
- The credential's rights are sized to the broadest task the agent might ever do, not the task in front of it.
- It persists between runs, so the agent holds production access even when it is idle.
- Nobody narrows it later, because narrowing risks breaking a future task.
That is least privilege inverted: maximum standing access, justified by convenience. The operational fix is to stop provisioning access at setup and start provisioning it per task.
The operational move: just-in-time, scoped, expiring
Least privilege becomes real when access is granted at the moment of use, scoped to the specific task, and revoked when the task ends. The agent never holds a standing key, because there is no standing key to hold. Each session gets exactly the access it needs and loses it on disconnect.
An identity-aware access gateway is how you operate that. With hoop.dev in front of the agent's database and infrastructure connections, the agent authenticates per session and receives just-in-time access scoped to the task, instead of a broad permanent credential. One clarification: hoop.dev governs the infrastructure connection the agent opens, not the model. It does not read the prompt or output. Least privilege here means the privilege on the connection, which is the access that can actually hurt you.
What this looks like day to day
- The agent starts a task and requests access through the gateway, authenticating as a named identity.
- It receives scope for that task: read on these tables, exec on this service, for this window.
- It works, every command recorded at the boundary.
- The session ends and the access is gone. Nothing standing is left for an attacker or a bug to reuse.
The contrast is sharp. A standing credential grants everything forever and hopes the agent behaves. Just-in-time scope grants only this task's access and ends it on disconnect. One trusts; the other bounds.
There is an objection worth addressing: doesn't an agent need broad access precisely because you cannot predict its tasks? The answer is that you do not have to predict tasks to scope access. You scope at the moment the task is known, which is session start, not setup time. The agent declares what it is about to do, receives access for that, and works. The unpredictability of the next task is handled by the next grant, not by a permanent credential sized for every possible future.
This is also where least privilege stops being a paperwork exercise and starts being enforced. A narrow service account documented in a policy still grants standing access; the policy describes intent, not enforcement. A grant that exists only for the session and expires on disconnect enforces the intent mechanically. The privilege is least because the system makes it least, not because someone wrote down that it should be.
FAQ
Won't per-task scoping slow the agent down?
Provisioning happens at session start, not per command, so the agent works at full speed inside the grant. What you lose is the idle standing access, which was pure risk.
Does the gateway use the agent's prompt to decide scope?
No. It governs and scopes the infrastructure connection. It does not read the model's prompt or output.
How is this different from a narrow service account?
A narrow account is still standing access; it just leaks slower. Just-in-time scope removes the standing grant entirely and ties each grant to a recorded session.
Least privilege is operational only when the standing key disappears. See just-in-time scoped access on the hoop.dev getting started guide, and read the code at github.com/hoophq/hoop.