AI agent approval controls: rules versus clear decisions
AI agent approval controls can replace fragile rules for many local agents. Compare policy maintenance, clear prompts, secret handling, and audit evidence.

An AI agent does not need a miniature enterprise authorization program every time it needs an API token or an SSH key. Most teams need three decisions that stay understandable under pressure: is the secret store available, may this agent process act in this run, and does this particular credential require a fresh human decision?
Policy engines can answer far more questions than that. They can also turn every permission change into a small software project, with inputs to trust, rules to test, exceptions to explain, and failures that arrive when someone edits a condition at the worst possible time. Use a rule engine when your access problem truly has variable ownership and constraints. Do not use one as decoration around a simple approval boundary.
A rule engine turns authorization into software maintenance
A policy engine is code, whether its syntax looks like code or not. Someone must define the available facts, write the rules, decide precedence, test changes, publish versions, investigate unexpected matches, and retire rules that no longer fit the organization.
That work can be justified. A company may need different resource owners to set access conditions, restrict actions by region or environment, or apply legal and contractual requirements. In those cases, a small fixed control set may force unrelated cases into one blunt approval. The mistake is treating this complexity as free because a policy language hides it behind declarative syntax.
Consider a familiar rule:
allow if
agent.project == "payments"
and request.host ends_with ".internal.example"
and request.method in ["GET", "POST"]
and time.weekday in ["Mon", "Tue", "Wed", "Thu", "Fri"]
It reads sensibly until someone has to answer operational questions. Who assigns agent.project? Can the agent influence it? Does ends_with accept not-internal.example? What does POST allow at an endpoint that can create, refund, delete, or trigger a transfer? What happens during an incident on Saturday? Does a later deny override an earlier allow?
Each question adds semantics. Each semantic needs a test. Each exception becomes part of the permission model, even if it lives in a hurried chat message and gets copied into a rule a week later.
Open Policy Agent documentation correctly describes policy as code and recommends testing it. That is not a marketing slogan for flexibility. It is an admission of the operational contract: if a policy controls meaningful access, the team must treat edits like code changes. Reviewers need fixtures. CI needs expected decisions. An on-call engineer needs a way to tell which policy version allowed a request.
Many teams skip that contract. They paste a few rules into a configuration file, then discover six months later that nobody knows whether a denial came from a typo, a missing input, or an intended boundary. An AI agent makes that failure more visible because it generates unusual sequences of calls and can exercise an overlooked branch far faster than a human operator.
Fixed controls reduce the maintenance surface by refusing to express arbitrary conditions. That sounds limiting because it is limiting. The useful question is whether the limitation excludes a requirement you actually have, or merely excludes a future rule someone might someday want.
Decision clarity matters when a call has consequences
An operator must be able to state why a call was allowed in one sentence. If the answer requires reading a rule bundle, resolving precedence, and inspecting agent-provided attributes, the operator cannot reliably approve or revoke access during an incident.
Clear decisions also prevent a quiet category error: a rule can make an action technically permitted without making it intelligible to the person who bears the consequences. A prompt that says an unnamed process requested access to a generic capability gives the operator almost nothing to judge. It is ceremony, not approval.
A useful authorization screen answers concrete questions:
- Which executable asked to act, and who signed it?
- Is this a new process or a process already approved for this session?
- Which credential will the action use?
- Where will the request go, or which host will SSH contact?
- Is the person approving one run or one sensitive use?
The first item deserves more respect than it usually gets. Agent names are labels. Process identity is evidence. A process can call itself release-agent, while a code-signing authority or an executable path gives the reviewer something that survives a renamed shell script. Identity evidence does not prove that every instruction is safe, but it narrows the question to a real principal.
NIST Special Publication 800-207 frames zero trust around explicit verification and continuous evaluation rather than inherited network trust. The practical lesson for local agent actions is simpler than many implementations make it: evaluate the actor and the request at the point of action. Do not grant a token to an agent and hope that the boundary remains meaningful after the token leaves your control.
Decision clarity is also a security property. When people can predict an approval, they can spot an unexpected one. If a coding agent that normally reads issue data suddenly asks to use a production write credential, the difference should be obvious before the call leaves the machine.
Identity, authority, and secret use are different questions
Teams often put three separate questions into one policy statement and then cannot tell which assumption failed. Keep them apart.
Identity asks who made the request. For a local agent, this can include the process, its code-signing authority, its parent process, and its lifetime. A human-readable agent label can help, but it should not carry the security decision by itself.
Authority asks whether that identified process may perform actions in this run. A session approval fits this question. It records that a person examined a new process and allowed it to use a defined action gateway until it exits or the operator revokes it.
Secret use asks whether the particular API key or SSH key may be used for this action. This is where a vault gate and per-credential approval belong. A locked vault should deny every action, regardless of an earlier session decision. A particularly sensitive credential may demand a human approval every time, even when the process already has session authority.
Conflating these questions creates predictable mistakes. A team approves an agent process once, then treats that approval as permission to use every credential. Or it unlocks a vault and mistakes availability for authorization. Or it writes a policy that checks a process name and a target host, yet allows the agent to retrieve the token and reuse it elsewhere.
The last failure matters most. If an agent holds plaintext credentials, your policy checked only the first use. The agent can pass the value to a subprocess, include it in a log, send it to another service, or use it after the original approval expired. A gateway that keeps secrets out of the agent changes the boundary: the agent requests an action, and the gateway performs the authenticated action itself.
That distinction is sharper than “secret masking.” Redacting an output after a token reaches the agent does not remove the token from its memory, prompt history, shell environment, or child process. Preventing delivery to the agent removes an entire class of accidental reuse.
Three explicit controls cover the ordinary agent case
A small control set works when each control owns one decision and none pretends to solve the others. For local developer agents, three controls cover a large share of the real risk without producing a policy language.
First, use an absolute vault gate. While the vault is locked, every action fails. This gives the operator a physical and conceptual stop condition. It should not depend on a rule evaluation, a remembered session, or a network check. On a Mac, hardware-gated unlocking through Secure Enclave and Touch ID can make this decision especially clear: the operator has opened the vault, or has not.
Second, authorize a newly seen agent process for its lifetime. The approval should identify the process in a way that resists a friendly name change, then expire when that process exits. This control avoids a prompt for every harmless request while refusing to make approval permanent by default.
Third, mark selected credentials for approval on every use. Use this sparingly and deliberately. A deployment credential that can change production infrastructure, an SSH identity with broad host access, or a token that can move money may justify an immediate decision for each call. A read-only development token that an agent uses repeatedly usually does not.
The resulting decision ladder is easy to reason about:
if vault is locked:
deny action
else if this agent process has no current session approval:
ask for session approval
else if the selected credential requires approval per use:
ask for credential approval
else:
execute the action
This is not a substitute for least privilege. The credential must still have a narrow scope, and the request path still needs transport security and target validation. The ladder makes the human control point explicit. It does not transform an administrator token into a safe credential.
The order matters. A per-call prompt should never bypass a locked vault. A remembered session should never bypass a credential marked for repeated approval. With a general rule engine, those precedence relationships often live in separate policies and become surprisingly hard to audit. With a fixed ladder, the order is the model.
A policy engine earns its cost when ownership varies
A policy engine is justified when the authorization decision must vary across many independently owned resources and that variation cannot be represented by credential choice or a small set of approval classes.
Suppose a shared automation service handles several business units. Each unit owns different repositories, cloud accounts, and data stores. Owners need to grant temporary access to defined groups, impose different retention conditions, and audit decisions under a central governance process. A policy layer may be the right design because the organization needs delegated rule ownership and consistent enforcement across a large estate.
A second good case is a server-side service that receives requests from many untrusted clients. The service may need to evaluate tenant, role, object ownership, request origin, and transaction state before it acts. A fixed local session approval cannot replace that. The server must make a decision for every request, even when no human sits nearby to approve it.
Do not stretch these cases into a reason to put a policy engine in front of every local coding agent. A developer machine usually has a smaller question: may this signed agent process use this stored credential through this action gateway while the operator allows it? The human already has local context. Adding conditions about time windows, project tags, and speculative risk scores can produce more false confidence than control.
There is another hard boundary. Policy cannot repair an overbroad credential. A rule may allow only requests to one host, but if the agent can extract the bearer token, the token's issuer must enforce its own scope. Keep the secret in the gateway and scope it at the provider. Treat gateway authorization as one layer, not a replacement for resource-side access control.
Approval fatigue means the scope is wrong
Repeated prompts make people faster, not more careful. If a person sees the same approval card twenty times while an agent fetches repository metadata, the person learns that clicking allows work to continue. The eleventh request that differs in a meaningful way then receives the same reflex.
The common answer is to build smarter rules that suppress prompts under increasingly specific conditions. That often swaps visible fatigue for invisible complexity. Someone writes an exception for read calls, then discovers that a supposedly read endpoint triggers a remote computation or exposes data that should have required review. The approval count falls while the decision becomes harder to inspect.
Set the approval scope according to the human judgment required. A session approval says, “I recognize this process and allow it to work with the ordinary credentials assigned to this run.” A per-call approval says, “This credential use has enough consequence that I will inspect it individually.” Neither prompt should exist simply because an implementation wants a confirmation dialog.
Good credential design makes this easier. Split credentials by consequence instead of keeping one powerful token and hoping a policy filters every call. Give the agent a narrow token for normal development work. Keep the production-changing token separate and demand an explicit decision when it is used. This may create more credentials, but it removes fragile request parsing from the authorization boundary.
A rejected recommendation deserves a direct answer: “Require approval for every agent action” sounds safe because it creates a complete record of human clicks. It is usually wrong for repeated, low-consequence calls. People cannot inspect a flood of similar requests well. Require approval where the reviewer can make a distinct judgment, and log the rest so the team can investigate actual behavior.
A harmless rule can authorize a damaging request
A common failure starts with a team that wants to permit an agent to update a staging service. They configure a rule that allows POST requests to api.example.internal when the agent claims the staging project. The agent receives a token in its environment because the gateway cannot inject it directly.
During a debugging task, the agent follows a copied command that uses the same hostname but a management endpoint. The endpoint accepts POST and supports an operation that promotes a configuration to production. The policy sees an allowed method, an allowed host, and an allowed project label. It returns allow.
The team may call this a policy bug, but there are several failures:
- The method was too broad to describe intent.
- The agent-controlled project attribute did not establish ownership.
- The host contained endpoints with very different consequences.
- The token existed outside the enforcement point and could be reused after the request.
- The operator never saw a decision that distinguished staging updates from production promotion.
Adding route patterns may close this particular hole. Then someone adds a versioned path, an alternate hostname, a batch endpoint, or a query parameter that changes behavior. The policy grows because the underlying credential does too much.
A better design splits the staging and production credentials. The normal session can use the staging credential through the gateway. The production credential requires a per-use approval, and the approval identifies the target and action. The gateway injects the credential and returns the result, while the agent never receives its value.
This design still relies on the API provider to scope both credentials correctly. It also does not prevent an approved agent from making a bad staging change. It does ensure that a staging workflow cannot quietly inherit production authority through a loose rule and a reusable token.
Test denial paths before an agent tests them for you
Authorization tests should prove that the system refuses actions under expected conditions, not merely that a normal request succeeds. The useful test cases are small enough to run before a team changes credentials or agent integrations.
For a fixed decision ladder, write the expected outcomes as a table and keep it beside the implementation:
| Vault state | Session approval | Credential setting | Expected result |
|---|---|---|---|
| locked | present | ordinary | deny |
| unlocked | absent | ordinary | request session approval |
| unlocked | present | ordinary | execute |
| unlocked | present | per-call | request credential approval |
| unlocked | revoked | ordinary | deny or request a new session approval |
This table detects a serious class of regressions: an engineer adds a convenience path that checks session authority before vault state, or lets a remembered process skip a per-call credential decision. The table makes the intended order reviewable without learning a policy language.
For a policy engine, test more than examples that should allow. Test missing attributes, malformed URLs, alternate hostnames, policy version changes, rule conflicts, clock changes, and explicit denies. Open Policy Agent's testing model supports rule tests, but the difficult work remains yours: decide the inputs that an attacker, a buggy agent, or a future integration can influence.
Also test revocation while an agent is active. Start a session, approve it, perform an ordinary action, revoke access, then repeat the same request. The second attempt must produce a denial at the action gateway. A revocation that only changes a dashboard record but leaves a process holding a usable credential has not revoked the effective authority.
For HTTP, inspect the returned result for enough context to diagnose failure without exposing authorization headers. For SSH, confirm that the helper uses the selected identity to connect but does not hand private key material to the calling agent. These details sound mundane until an incident forces a team to establish what the process actually possessed.
An audit log must answer a different question than a prompt
Approval controls prevent or allow an action in the moment. An audit log tells you what happened later, who approved it, and whether someone altered the record. Do not merge those jobs into a vague “accountability” feature.
A useful event record captures the session identity, the decision made, the credential reference rather than its secret value, the action type, target, outcome, and ordering information. It should also capture session revocation. Without that link, investigators can see a request but cannot tell whether it occurred before or after an operator withdrew approval.
Tamper evidence needs careful wording. A hash chain can make later modification or deletion detectable when a verifier has the expected chain data. It cannot prove that a compromised system recorded every event in the first place. It also cannot decide whether an approval was wise. The log gives you evidence about recorded history, not a time machine.
For a local gateway, a write-blind encrypted audit log provides a useful split: the component that executes actions records events, while routine readers consume projected journals rather than rewriting history. Offline verification is especially useful because it does not require an available service or a decryption key merely to check chain structure.
Sallyport records agent runs in a Sessions journal and individual actions in an Activity journal, both projected from an encrypted hash-chained audit log. Its sp audit verify command checks the chain offline over ciphertext, which is the right direction for a log that may matter after the machine has become suspect.
Keep audit review practical. When an agent surprises you, first identify the process that received session approval, list the actions in time order, revoke the active session, and examine the affected provider logs. The local journal explains what crossed the gateway; the destination service explains what the remote system accepted.
Choose the smallest decision model that you can operate
Start with the actual authority path, not an abstract desire for flexibility. List the credentials an agent needs, identify which ones carry a consequence that merits a fresh approval, and decide how a person can revoke an active process. If that produces three stable decisions, keep them explicit.
Adopt a policy engine when the organization needs rule ownership and variation that a credential split plus session and per-call approval cannot express. Then accept the obligation that follows: version policies, test adversarial inputs, document precedence, assign owners, and review exceptions as carefully as code.
The bad design is not “rules” or “prompts.” The bad design is an authorization boundary that nobody can explain while an agent is waiting to act. If your team cannot state why a request is allowed, make the decision model smaller before you make it smarter.
FAQ
What is the difference between a policy engine and approval controls for AI agents?
A policy engine evaluates rules against context, such as an agent identity, target host, method, time, or data classification. Fixed approval controls expose a small number of stable decisions, such as whether the vault is open, whether this agent run may act, and whether this credential needs a human approval now. The first model buys flexibility; the second buys a decision path that people can explain and test.
Do AI agents ever need a policy engine?
Yes, when different teams own different resources, permissions vary by environment, or compliance requires centrally managed access rules. The cost is ongoing rule ownership, testing, review, and incident response. Do not adopt one merely because the agent can perform complicated tasks.
Should I approve an agent session once or every API call?
Per-session approval is usually the better default for a development agent that makes several related calls in one run. Per-call approval fits credentials with unusually high consequences, such as production write access or a payment operation. The dangerous middle ground is approving a broad session without limiting which credentials it can use.
Why should vault access and agent authorization be separate?
A vault lock is an absolute condition: no action can use a secret while the vault is locked. Authorization answers a different question: whether a specific agent process may ask for actions after the vault is available. Treating these as separate controls prevents a session approval from becoming an excuse to act while the operator has withdrawn access.
Can session approval be unsafe for autonomous coding agents?
Yes, if the agent can obtain a broad token and then make arbitrary calls without another decision. A process may begin with a harmless task and later receive an instruction to read, modify, or send something harmful. Session approval needs a narrow credential set and a reliable way to end the approval when the process exits.
Which credentials should require per-call approval?
Require repeated approval only for credentials whose misuse has a sharply higher cost than normal development actions. Asking on every low-risk call trains people to approve without reading. A prompt should appear because a person must make a distinct judgment, not because the software has run out of ideas.
What should an AI agent action audit log record?
Log the agent process identity, the authorization decision, the credential reference, target, action type, outcome, and a record that exposes tampering. Avoid recording secret values or complete sensitive payloads unless you have a separate retention design for them. An audit trail that cannot tell you which executable received approval is much less useful after an incident.
How do I decide whether my team needs rules or fixed controls?
Start with a table of the agent actions your team allows today, the credentials each action needs, and whether a human must decide at session start or at every use. If most rows differ only by a fragile mix of request fields, you are designing a policy program. If they differ by a few clear ownership boundaries, explicit controls will usually be easier to operate.
Why do authorization policies become hard to maintain?
Policies fail when nobody owns their semantics, when rule changes lack tests, or when exceptions accumulate after a production outage. They also fail when the available inputs do not prove the thing the rule claims to authorize, such as trusting an agent-supplied project label. A rule that reads well but relies on forgeable context is not a control.
Does a tamper-evident audit log replace approval prompts?
No. A tamper-evident log can show that records changed or disappeared after the fact, but it cannot make an overly broad approval safe. Use approvals to constrain action before it happens, then use the journal to investigate, revoke, and improve the design afterward.