Blog · Guardrails
Least privilege for agents: scope the connection, not the prompt
October 14, 2026 · The Murmurator team
Least privilege is old advice, and teams generally believe they follow it. Then an agent gets added to the system and the principle quietly lapses, because the convenient thing is to reuse the integration token that already exists — the one with full workspace scope, created two years ago for a script.
The agent now holds every permission that token holds. Not the permissions it needs; the permissions it has. Those are rarely close.
Why agents make this worse
With ordinary software, over-broad credentials are a latent risk. The code calls three endpoints, and it will keep calling those three endpoints until someone changes it. You can read the code and enumerate the behaviour.
An agent chooses its calls at runtime, from whatever the credential permits, based on text that may include content from strangers. The gap between granted and used stops being latent and becomes reachable — through a misread instruction, an unusual input, or a deliberate injection. Over-permissioning that was theoretical for a script is live for an agent.
Deriving the scope
Start from the operations, not the integration.
1. Enumerate what the workflow actually does. Not the integration it uses — the specific calls. "Reads open tickets in the Billing view, posts internal comments, sets priority." Three operations.
2. Find the narrowest credential that permits exactly those. This is tedious and it's where the work is. Most platforms offer more granularity than people use:
- OAuth scopes: request
channels:readandchat:writeto one channel, notchat:writeplusadmin. - Database roles: a role with
SELECTon four named tables beats a read-only user with access to the schema. - API tokens: many providers support per-resource restriction — a GitHub token scoped to one repository, a Stripe restricted key with read on charges and nothing else.
- Cloud IAM: a role with three actions on one bucket prefix.
3. Write down what the credential allows beyond the three operations. There will always be a residual. The question is whether you can live with it.
4. For each residual capability, ask what a wrong call costs. If the answer includes "customer data leaves the building" or "money moves," go back to step two and keep narrowing. If it's "an internal comment lands on the wrong ticket," that's an acceptable residual.
Separate credentials per workflow
The instinct is one connection per service, shared by everything. It's less to manage and it's the wrong shape.
Shared credentials mean the permission set is the union of every workflow's needs. The ticket triager inherits the billing reconciler's write access to invoices, because they're both "the Stripe connection." Every workflow added widens the grant for all of them, permanently, and nobody notices because nothing breaks.
Per-workflow credentials cost more to set up and give you three things: a permission set that stays minimal, an audit trail that identifies which automation did what, and the ability to revoke one workflow without taking down the rest. The third one matters at exactly the moment you're least able to do careful work.
Read and write are different connections
A pattern worth adopting as a default: never grant read and write through the same credential when the workflow's reads are the risky part.
An agent that reads untrusted content and also holds write access is the injection scenario in its purest form. Splitting them — a read connection for the untrusted source, a separately-scoped write connection for the specific narrow action — means the component processing hostile text has nothing to offer an attacker.
This costs a little structure and removes an entire attack class. It's the highest-leverage change most teams can make.
Time and volume are scopes too
Permissions are usually thought of as what. They should also cover how much and when.
- Per-run caps. A triage workflow handling one ticket should not be able to make four hundred writes. A ceiling turns a runaway loop into a failed run.
- Rate limits per connection. Independent of what any single run does.
- Expiry. Credentials for a workflow built for a quarterly migration should stop working after the quarter. Long-lived tokens for short-lived automations accumulate, and nobody audits them.
- Time windows. A workflow that only ever runs during business hours can have a credential that only works then. It's a cheap constraint that makes off-hours abuse visible.
The review that catches drift
Scope is not a one-time decision, because workflows grow. Someone adds a step, needs one more permission, widens the credential, and ships. Nothing in the system objects.
A quarterly pass that's worth the hour:
- For each connection, list the operations actually invoked in the last 90 days, from your run logs.
- Compare against what the credential permits.
- Anything granted and unused for a quarter gets removed.
- Anything used once by one workflow probably wants its own credential.
The data for this only exists if runs are logged with the operation they performed. That's a good reason to log them, separate from debugging.
The framing that helps
Stop thinking of it as "the Slack connection." Think of it as "the set of things this automation can do to Slack on its worst day."
The second framing makes the question concrete, makes over-permissioning feel like the decision it is, and tends to produce narrower grants without anyone having to argue for a policy.
Turn one person's AI process into the company's.
Murmurator is invite-only. Already invited? Sign in and build something real.