Deciding What an AI Agent Is Allowed to Touch: the Permissions Boundary That Survives a Bad Day

A blast-radius decision framework for the write access an agent gets — and what recovery looks like on the day it does the thing wrong.

Author
Prabhash Jha
Published
Reading time
16 min read

The interesting question about an AI agent is not “can we make it do the thing?” It is “what does the recovery look like the day it does the thing wrong?”

Most writing about AI agent permissions is either identity-management vendor content (Okta-shaped diagrams, scope tables, OWASP taxonomies) or enterprise-security compliance framings (SOC 2 evidence, EU AI Act cross-references). Both are useful in the right context and neither is what a small operator actually 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 is the worst plausible outcome on a bad day, and what does the recovery from that look like?

This post is that framework, written from having actually handed agents write access to this website. Everything below is either something I do, or something I have decided the recovery cost of doing is too high to justify the convenience. It is not a security-vendor pitch and it does not sell you a policy engine.

Why “least privilege” is the wrong first question

The industry-standard framing is least privilege: give an agent only what it strictly needs. That is a fine principle but it is a 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:

  1. Classify the action by blast radius. Not by whether it can be done — anything an API supports can be done — but by what happens if it goes wrong and cannot be undone. This is where most permissions decisions should start and where they almost never do.
  2. Decide whether the action belongs to a class you will let agents perform at all. Some classes just do not, no matter how tightly scoped the token is.
  3. Only then, for the actions that pass the first two gates, apply least privilege to the specific scopes and tokens.

Skipping steps 1 and 2 is how you end up with an agent that “just needs delete permission for that one folder” and a bad day later has removed something you cannot get back.

The blast-radius taxonomy that decides everything else

There are essentially four classes of action, and 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. The recovery from a bad Class 1 action is that the agent tries again. There is 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. The 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. The 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. The 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 are not 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.

The specific things I let my agents do

For concreteness, here is the exact scope I grant on this site, mapped to the classes above. This is not a template — your operation is different — but it is 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 is no recovery cost because reads do not 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 is caught by check-posts, check-links and check-search before it lands, and 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 of these are auditable in the repo history and 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” is not 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 cannot 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 — but the commit that lands them has to be one I read, not one the agent authored. This is a real friction on the agent, and it is a friction I want.

Class 4, hard-blocked: anything to do with Cloudflare account settings, DNS, or Access rules. The account credentials are not 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 is 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. The 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 is not really Class 2 — it is 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 cannot 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 is faster to grant everything and narrow later. Then the demo works, the demo becomes staging, staging becomes production, and 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 and it is impossible after go-live because now real work 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 and it is 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 does not 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, because the recovery clock does not start until somebody notices, and if nobody notices then there is no recovery — there is just accumulated damage. The audit trail is what 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 is not documentation, it is the containment measure.

The “does the human belong here?” question

Once you have 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 is the wrong answer, and it is 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 is not a control, they are 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:

  1. 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 will not 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.
  2. 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 is much lower than most systems assume — I use “if I would open every one of these individually, it is under the threshold; if I skim, it is not”.

Where a human check is theatre, the honest answer is not “add a better checklist”. It is either: automate the specific decision entirely (the check is not 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, because 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. If any of the three is missing, the permission has not been granted responsibly — it has 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 — 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; the very short version is that 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 does not exist, the action is not really recoverable — it is 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, and all three are things I have used at least once.

Without a real kill switch, the permission is not a permission — it is a fait accompli. Grant nothing you cannot 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 is not idle — it is 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 are needed, with a short TTL and automatic revocation.

The just-in-time model is: the agent asks for the permission when it needs it, gets a token with a lifetime measured in minutes not months, and the token expires whether the agent needed to use it or not. If the agent does not 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.

This is more work to set up. It is 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 are 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 have not 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 is what tells you why the agent did what it did; the permissions are what limit what the agent could have done at all. Together they are what make an autonomous system operable.

If your problem is upstream — you have not 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 is minutes; for a batch job that runs in a loop, it is the length of the loop plus a small buffer. If you cannot 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 is not automated. The agent can prepare the action, log the request, and page a human — but 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” is not a kill switch. If rotating the token or disabling the trigger is not a single documented command you have run at least once, you do not 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 will not 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, and 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 have not 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; and 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.

Keep reading