AI Agent Permissions: Read, Draft, Approve, Execute
Design AI agent permissions enforced in code, not prompts: action classes, exact-action approval, expiry, one-time use, revocation and the negative tests that prove it.
Contents
- Classify actions before granting permissions
- Put enforcement outside the prompt
- Design a readable exact-action preview
- Bind approval to the exact operation
- Handle revocation, cancellation and uncertain outcomes
- Test the denial paths
- Apply the policy to a personal workflow
- Frequently asked questions
- Is asking the model to seek permission enough?
- Should every read operation require approval?
- What if an approved action changes before execution?
- Can rolling back local state undo a sent email?
Image: Filip Szalbot on Unsplash.
An AI agent's permissions should be enforced by the runtime, not requested in a prompt, and every consequential action should run only with approval for that exact action. Approve "send this reply to Sam," and a reply to someone else, or with different text, needs a new approval.
Here is the case this guide is built around.
You approve a draft to Sam.
Before it sends, the agent "improves" it and adds Alex.
The old approval should now be worth nothing.
This guide is part of the AI harness engineering guide.
Classify actions before granting permissions
Not every action needs the same control. Sort them first.
| Class | Examples | Default control |
|---|---|---|
| Read | List events, search notes, read a thread | Allowed within scope, logged |
| Draft | Write a reply, propose an event, prepare a file | Allowed; the output is held for review, nothing leaves |
| Execute, reversible | Create a private note, add a tentative hold | Approval, or a narrow standing rule you wrote |
| Execute, external | Send a message, invite people, post publicly | Exact-action approval every time |
| Irreversible or financial | Delete data, pay, sign, cancel accounts | Exact-action approval plus a second check, or not allowed at all |
Two dimensions matter: whether the effect leaves your control, and whether it can be undone. A sent email cannot be unsent. A deleted file may be gone for good. Treat those classes as the most expensive.
Most personal workflows deliver their value at the draft stage. Start there.
Put enforcement outside the prompt
The model proposes. The runtime decides.
A system prompt that says "always ask before sending" is a preference the model usually follows. A harness where the send tool checks for a valid approval before executing is a rule it cannot skip. Prefer rules:
- Remove tools a task does not need. No send tool means no accidental sending.
- Scope credentials so a tool cannot reach other accounts or resources.
- Check policy in code before every execution, in a component the model cannot modify.
- Apply downstream limits too, such as read-only scopes at the provider.
Layered controls matter because any single one can fail.
Design a readable exact-action preview
An approval is only meaningful if you can see what you are approving. A good preview shows:
| Field | Example |
|---|---|
| Action | Send email |
| Account | work account |
| To | sam@example.com |
| Subject | Re: Project Alpha beta |
| Body | Full text, not a summary |
| Attachments | None |
| Reversible? | No. Delivered email cannot be recalled |
| Expires | 15 minutes |
Show the full content. "Send a short reply confirming the date" is not an approval of the actual reply.
Be honest about reversibility. If an action cannot be undone, say so on the preview, not in documentation.
Bind approval to the exact operation
OWASP's AI Agent Security Cheat Sheet states the rule precisely: before execution, check that the approval belongs to the current actor and the exact tool call, remains valid and has not already been used, and check and consume it in one atomic step so concurrent or repeated requests cannot reuse it (OWASP).
In practice, an approval record holds:
{
"approval_id": "apr_7f3c",
"actor": "you",
"tool": "email.send",
"action_digest": "sha256 of the canonical tool name and every argument",
"created": "2026-10-18T09:12:00Z",
"expires": "2026-10-18T09:27:00Z",
"used": false
}At execution time the runtime recomputes the digest from the actual call. If anything differs, a recipient, a word, an attachment, the approval does not match and the action is refused.
The state machine is short:
- Proposed. The agent prepares the action; nothing has happened.
- Awaiting approval. You see the preview.
- Approved. An approval record exists for this digest.
- Executing. The runtime atomically checks and consumes the approval, then runs the action.
- Done, failed or uncertain. The result is recorded.
Any change to the action before step 4 sends it back to step 1.
Handle revocation, cancellation and uncertain outcomes
Expiry. Approvals should expire. Resuming a task tomorrow should not reuse today's consent.
Revocation. If you revoke a connector or credential, pending approvals that depend on it are void.
Cancellation. Cancelling a task stops new actions. It cannot undo completed ones, so report exactly what already happened.
Uncertain outcomes. If a send times out, the email may or may not have gone. Do not retry blindly. Check the sent folder or the provider's API first, then decide. The scheduling guide covers this reconciliation step in depth.
Test the denial paths
Permissions are only real if the failure cases are tested. Write these before you connect a real account:
| Test | Expected result |
|---|---|
| Execute with no approval | Refused; nothing sent |
| Execute after approval expired | Refused; new approval requested |
| Approve, then change the recipient | Refused; digest mismatch |
| Approve, then change one word of the body | Refused; digest mismatch |
| Reuse a consumed approval | Refused |
| Two concurrent executions of one approval | Exactly one succeeds |
| Execute after revoking the credential | Refused at the tool or provider |
| A document instructs the agent to send | No send occurs without your approval |
Check the downstream state, not just the agent's message. "I didn't send it" is a claim; an empty sent folder is evidence. The evaluation guide shows how to fold these into a full suite.
Apply the policy to a personal workflow
Start with the strongest version of the policy: no execution tools at all. The draft-only email tutorial builds a useful assistant that way. When you later add a consequential action, add it through this approval design and these tests, and connect it through a scoped tool as shown in the MCP tutorial.
The order matters:
read first,
then draft,
then approve,
then execute,
one capability at a time.
Frequently asked questions
Is asking the model to seek permission enough?
No. Models usually follow such instructions, but nothing guarantees it. Enforce approvals in code the model cannot change.
Should every read operation require approval?
Usually not. Scope reads tightly and log them instead. Reserve approvals for actions with external or irreversible effects.
What if an approved action changes before execution?
The approval no longer matches and the action is refused. The new version needs its own approval.
Can rolling back local state undo a sent email?
No. Local rollback restores your system's records, not effects in the outside world. Treat external actions as permanent.