The real question about an AI agent isn't "can we make it do the thing?" It's "what does the recovery look like the day it does the thing wrong?"
Most writing on AI agent permissions splits into two piles. One is identity-vendor content, all Okta-shaped diagrams and scope tables and OWASP taxonomies. The other is enterprise-security framing, SOC 2 evidence and EU AI Act cross-references. Both are useful somewhere. Neither is what a small operator needs on the day they hand a machine the keys to their git repository or their live production site. What they need is a decision framework that answers one question honestly per action the agent could take: what's the worst plausible outcome on a bad day, and what does the recovery from that look like?
This post is that framework. I wrote it from having actually handed agents write access to this website. Everything below is either something I do, or something where I've decided the recovery cost is too high to justify the convenience. It isn't a security-vendor pitch. It doesn't sell you a policy engine. It's the shape of the decision itself, written for the person who's going to eat the consequences.
The framing is deliberately small-operator. A team of one, two, or five, running unattended jobs against their own infrastructure. The reason that framing matters is that most permissions writing assumes a security team behind you. There isn't one. You are the security team. The framework has to fit in your head, not in a compliance binder.
Why "least privilege" is the wrong first question
The industry-standard framing is least privilege: give an agent only what it strictly needs. Fine principle. Very late one. It answers "how much access?" without first answering "which class of action is safe to grant any level of access to?"
The order that actually helps a small operator is:
- Classify the action by blast radius. Not by whether it can be done. Anything an API supports can be done. Classify by what happens if it goes wrong and cannot be undone. This is where permissions decisions should start and where they almost never do.
- Decide whether the action belongs to a class you'll let agents perform at all. Some classes just don't, no matter how tightly scoped the token is.
- Only then, for the actions that pass the first two gates, apply least privilege to the specific scopes and tokens.
Skip steps 1 and 2 and you end up with an agent that "just needs delete permission for that one folder". A bad day later, it has removed something you can't get back. The scope was narrow. The class was wrong. Nobody caught the difference because the vocabulary the industry gave you doesn't distinguish between them.
The blast-radius taxonomy that decides everything else
There are essentially four classes of action. The class is what determines whether an agent should ever touch the action. Not the API's scope list.
Class 1. Reversible by the agent itself, within seconds. The agent edits a draft. The agent runs a query and inspects the result. The agent generates content into a file the agent also owns. Recovery from a bad Class 1 action is that the agent tries again. There's no meaningful blast radius because the action never left the agent's own sandbox. Grant these freely. Not doing so is what makes AI agents feel useless.
Class 2. Reversible by a human in minutes. The agent commits to git. The agent pushes to a branch. The agent uploads a draft to a CMS. The agent enqueues an email in a "review before send" queue. Recovery is that a human notices, reverts, or reviews. The blast radius is real but bounded. A bad commit is a bad commit, and git revert is a real answer that costs about three minutes. Grant these, with the audit trail that lets the human notice.
Class 3. Reversible in hours or days, at real cost. The agent posts publicly. The agent sends email to a real list. The agent modifies a live production database. Recovery is that a human notices AND takes an action that itself has consequences. Deleting a public post. Sending a correction email. Rolling back a migration. Grant these only if the specific action's blast radius is small AND the audit trail lets you catch the bad case within minutes, not hours.
Class 4. Irreversible, or reversible only at business-changing cost. The agent deletes a customer record. The agent moves money. The agent changes account credentials. The agent posts something that gets picked up by the wire before the correction lands. Recovery is that you spend a week apologising or paying, and the trust cost is permanent. Do not grant these. Ever. No matter how competent the agent, no matter how narrowly scoped the token. The convenience of automating a Class 4 action is never worth the cost of getting it wrong once.
The lines between the classes aren't fuzzy in practice. What makes them feel fuzzy is that the industry sells you tools that can technically perform every action, and lets you decide which. The taxonomy above is the pre-tool decision. Before you write a single line of code that could touch a Class 4 action, ask yourself whether the action belongs in the code at all. If the answer is no, the tooling question never comes up. If the answer is yes, you've made a decision you can be held to on a bad day. That distinction is the whole point.
Notice what the classes are graded on. Time to recover, and cost of recovery. Not "how important is the system" or "how sensitive is the data". Sensitivity matters for other reasons. It isn't what changes the class of the action.
One case sits awkwardly across the taxonomy and is worth calling out, because it is the one most people ship first: an agent that only talks. No tools, no writes, nothing that looks like a Class 3 action anywhere in it. The trap is that a sentence said to a customer in your name can itself be a commitment you are held to, which moves it up the scale without ever touching an API. What actually breaks when you put a language model in a customer-facing flow works through that case specifically — the failure modes, what they cost, and why "it can only reply" is not the reassurance it sounds like.
The specific things I let my agents do
For concreteness, here's the exact scope I grant on this site, mapped to the classes above. This isn't a template. Your operation is different. It's a worked example of the framework.
Class 1, granted: anything that reads. Read repo files. Read the sitemap. Read the deploy logs. Read the digest. Read the worklist. Read the backlog. The publishing agent reads everything it can, all the time, and there's no recovery cost because reads don't change anything.
Class 1, granted: anything that writes to files owned by the agent's session and inspected before commit. Draft posts. Generated covers. Generated OG cards. Updated backlog metadata. The bad case is a bad draft. The recovery is "delete the file, try again".
Class 2, granted: commits to main when the build gate passes. This is the important one. I explicitly grant the agent the ability to write to the branch that Cloudflare Pages deploys, without a human review step, on the specific condition that npm run build returns zero. The build gate is what makes this a Class 2 action rather than a Class 3 one. A broken deploy gets caught by check-posts, check-links and check-search before it lands. A bad commit that passes the gates is still git revert-able within minutes.
Class 2, granted: pushes to origin/main. Same reasoning. The deploy pipeline has its own build gate on the far side, and Cloudflare Pages retains previous deployments for rollback. A single click undoes any single deploy.
Class 2, granted: GitHub API calls to create commits, open issues, update issue state on the worklist. All auditable in the repo history. All undoable by hand.
Class 3, considered and NOT granted: publishing to LinkedIn or any social platform under my name. The recovery cost of a bad post on LinkedIn is a deleted post that everyone who saw it also screenshot-shared, plus a reputational tax. The convenience of automating "post the article as a LinkedIn update" isn't worth that. This is the specific reason the site's AUTOMATION-PLAN document says explicitly "It does not touch LinkedIn or email". The class was considered and rejected, not just left undone.
Class 3, considered and NOT granted: sending email to the newsletter list. Same reasoning. The recovery from a bad email to a real list is a correction email that people also read as "these people can't keep their systems straight", plus unsubscribes that are permanent. Newsletters ship when a human clicks send.
Class 4, hard-blocked: deletion of any published post. Deletion of any subscriber record. Changes to _headers, _redirects, functions/, or package.json dependencies without an explicit re-review. The agent can PROPOSE these in a run log entry. The commit that lands them has to be one I read, not one the agent authored. It's a real friction on the agent. It's a friction I want.
Class 4, hard-blocked: anything to do with Cloudflare account settings, DNS, or Access rules. The account credentials aren't in the agent's environment at all. If they need changing, I change them.
The two questions to ask before granting an agent any action
Before you extend an agent's permissions to include a new capability, force yourself to answer both of these in one paragraph each. Not a checklist. Actual sentences.
Question 1: What's the worst plausible outcome of this action going wrong, and how long does the recovery take? Not the average outcome. The worst plausible one. If the agent could theoretically do the action ten thousand times before you notice, use that number, not one. "The agent could send one wrong email" is a Class 3 action. "The agent could loop and send the same wrong email to a thousand recipients before anything catches it" is a Class 4 action. Autonomy is what changes the class.
Question 2: What class of person is the recovery going to require, and are they going to be available on a bad day? A recovery that requires you personally to be reachable within 15 minutes for the recovery to still be a Class 2 action isn't really Class 2. It's Class 3 with a lucky timing assumption. Be honest about who else has the credentials to fix a bad case and how reliably they can be reached.
If you can't answer both questions to your own satisfaction in one paragraph each, the answer to "should I grant the action?" is no.
The three failure modes I have actually seen
Failure mode 1: "This is only for the demo". An agent gets a broader-than-needed permission during development because it's faster to grant everything and narrow later. Then the demo works. The demo becomes staging. Staging becomes production. Nobody remembers to narrow the permissions until the day the agent hits a case its narrowed-later self would have refused. Grant narrow from the first line, even during development. It takes ten minutes at the start. It's impossible after go-live because real work now depends on it.
Failure mode 2: "The scope doesn't include destructive actions". GitHub's repo scope, for example, includes deleting branches, force-pushing, deleting files. It looks like a read-write scope. It's actually a "do anything to this repository" scope. Read the scope's actual permissions before granting it. Not the scope's name. Most OAuth scopes bundle actions the caller doesn't intend to allow. The bundling is where the blast radius lives.
Failure mode 3: "We'll add monitoring later". Any Class 2 or Class 3 permission granted without the audit trail that lets you notice a bad action is silently a Class 4 action. The recovery clock doesn't start until somebody notices. If nobody notices, there's no recovery. Just accumulated damage. The audit trail defines the class as much as the action does. This is the whole argument in what to log when an AI agent acts on your behalf. Logging isn't documentation. It's the containment measure.
The "does the human belong here?" question
Once you've classified an action, one specific decision separates well-run automation from theatre. Do you put a human in the loop?
The industry default is yes, on anything Class 3 or above. That's the wrong answer, and it's the wrong answer for the same reason "just add a review step" fails everywhere else. A human who has to approve two hundred things a week isn't a control. They're a rubber stamp with a chair. The human check is only real if the human can actually tell good output from bad, and if the volume is low enough that they can pay attention.
Two rules that work in practice:
- A human check is only a control when the human can refuse. If refusing is expensive (blocks the release, delays the client, means a difficult conversation), the human won't refuse routinely, so the check is theatre. If the reviewer's job is to be right, not to be popular, and refusing is genuinely free, the check works.
- A human check on 20 items a week is a control; a human check on 200 items a week is not. Below a threshold, humans pay attention. Above it, they stop reading. The threshold varies by task but it's much lower than most systems assume. I use "if I would open every one of these individually, it's under the threshold; if I skim, it's not".
Where a human check is theatre, the honest answer isn't "add a better checklist". It's either: automate the specific decision entirely (the check isn't adding value; remove it), or reduce the volume until a human can actually make it (the check is important; the volume is the problem, not the check). Automation with a rubber-stamp step is worse than automation without one. The presence of the step deflects the blame away from the design that made the volume too high.
The specific artefacts a permissions decision needs
For every action class you grant to an agent, three specific artefacts have to exist. Miss any of the three and the permission hasn't been granted responsibly. It's been granted optimistically.
Artefact 1. The audit trail from outside the agent. Not the agent's own log of what it did. An external record. A git history. An API response log. An email queue with message IDs. Something that survives the agent dying, the process being killed, the machine losing power. The action's real evidence lives outside the actor. See the full argument in what to log when an AI agent acts on your behalf. Short version: the agent is the least reliable witness to its own actions.
Artefact 2. The recovery procedure, written down. A one-paragraph document per action class that says: "If action X fires wrong, do Y and Z in that order, and expect the recovery to complete in W minutes." If the procedure doesn't exist, the action isn't really recoverable. It's unrecovered but not yet detected. Write the procedure before the first time you grant the permission, not after the first time you need it.
Artefact 3. The kill switch. A single named place where you can revoke the agent's ability to perform this action within seconds. For me, on this site, the kill switches are: rotating the GitHub OAuth token (kills all write access), rotating the Cloudflare API token (kills the deploy verification), and setting the daily-run cron to disabled (kills the trigger). All three are documented. All three are one command each. All three are things I've used at least once.
Without a real kill switch, the permission isn't a permission. It's a fait accompli. Grant nothing you can't revoke in under a minute.
The single hardest one: standing versus just-in-time permissions
The most common mistake in agent permissions is granting standing access to a Class 3 action so the agent can "handle it when needed". Standing permissions are the reason Class 3 actions turn into Class 4 problems. An idle or compromised agent sitting on standing privilege isn't idle. It's exposed. This is why Microsoft's own guidance and industry security research on AI agent identities both converge on the same recommendation: grant elevated permissions only for the moment they're needed, with a short TTL and automatic revocation.
The just-in-time model looks like this. The agent asks for the permission when it needs it. It gets a token with a lifetime measured in minutes not months. The token expires whether the agent needed to use it or not. If the agent doesn't need the permission for the next hour, no exposure exists. If the agent is compromised in that hour, the attacker inherits a token that expires before they can pivot.
More work to set up. Also the difference between a permission model that survives a bad day and one that turns a bad day into a bad quarter. If you're only going to build one non-obvious piece of infrastructure for your agent, this is it.
What to do next Tuesday
If you already run agents on your own systems, do the following two exercises this week.
Exercise 1. Write down every action your agent can currently perform. Not the tool names. The actions. "Commit to git." "Send an HTTP POST to my analytics endpoint." "Read a database row." "Write a database row." For each one, mark the class from the taxonomy above.
Exercise 2. For every Class 3 or Class 4 action on the list, answer the three-artefact test: audit trail from outside, written recovery procedure, kill switch. Any action that fails on any of the three, either downgrade the action (revoke the permission until the artefacts exist) or take the time to build the artefact before the next run.
If the exercise takes an hour, you have a small operation and this is worth an hour. If it takes a week, you have a larger operation and the delay of doing it now is smaller than the cost of the first bad day you haven't prepared for.
Where this fits with the rest of the work
The permissions boundary is the containment side of running unattended agents. The audit trail is the diagnostic side, in what to log when an AI agent acts on your behalf. The log tells you why the agent did what it did. The permissions limit what the agent could have done at all. Together they're what make an autonomous system operable.
If your problem is upstream, if you haven't yet decided which tasks to hand to an agent at all, the framing in how to automate your work with AI is the earlier question. And if your specific failure mode is the workflow that runs green and does nothing, a silent Class 2 action pretending to be a completed one, the diagnosis is in the automation failure nobody catches.
FAQ
How long should a just-in-time agent token live?
Long enough for the specific action, and no longer. For a commit-and-push cycle that's minutes. For a batch job that runs in a loop, it's the length of the loop plus a small buffer. If you can't state the number in minutes, the token is standing access wearing a costume.
Should I put a human review step on every Class 3 action, or automate it fully?
Neither by default. If the reviewer can genuinely refuse without punishment and the volume is low enough that they read every item, keep the review. Otherwise pick one. Automate the decision entirely, or cut the volume until the review is real. A rubber-stamp step is worse than no step because it launders responsibility.
What if my agent needs a Class 4 permission for one specific edge case?
Then that edge case isn't automated. The agent can prepare the action, log the request, and page a human. The commit, the send, or the delete is done by the human. The convenience of automating one Class 4 case is never worth building the plumbing that could execute all of them.
How many actions is too many for one agent token?
Count the classes, not the actions. One token holding any mix of Class 1 and Class 2 actions is fine. A single token that spans Class 2 and Class 3 is where blast radius creeps in silently, because the audit expectations for the two are different. Split tokens along class boundaries, not along feature boundaries.
Do I need a kill switch if the agent only runs on a schedule?
Yes. A scheduled agent that has already fired and is mid-loop is exactly when you need to revoke access, and "wait for the next window" isn't a kill switch. If rotating the token or disabling the trigger isn't a single documented command you've run at least once, you don't have one.
Should the agent write its own audit log, or should I rely on external systems?
External systems. The agent is the least reliable witness to its own actions. A crashed, killed, or compromised agent won't finish writing its log. Git history, API response logs, and message queues survive the agent dying. The agent's own log is a convenience, not evidence.
What is the fastest way to audit permissions I have already granted?
List every action the agent can currently perform in plain English. Mark each with a class from the taxonomy. For every Class 3 or Class 4 line check the three artefacts: external audit trail, written recovery procedure, one-command kill switch. Any row missing an artefact gets revoked until the artefact exists. An hour of this work is cheaper than the first bad day you haven't prepared for.
The one-sentence version
Classify every agent action by blast radius before you classify it by scope. Refuse Class 4 actions entirely no matter how tightly scoped the token. Require three artefacts (external audit trail, written recovery procedure, one-command kill switch) for every Class 2 and Class 3 permission you grant. Never grant standing access to a Class 3 action when just-in-time will do. The permissions model that survives a bad day is the one designed around the bad day, not the good one.
Top comments (0)