An AI agent's authorisation policy changes every time someone adds a tool, widens a scope or edits a rule, and without regression tests the first sign of a broken policy is an agent doing something it should never have been allowed to do. This guide shows how to turn the agent permission model into a suite of automated tests that run in CI: allowed calls that must keep working, denied calls that must stay denied, delegation cases where the agent acts for a user, and injected calls where untrusted content tries to steer the agent into a tool it should not touch. It is for platform engineers, security engineers and AI engineers who own agent tool gateways, MCP servers or policy engines. API-level authorisation testing (BOLA, BFLA, test identities) is covered in the Authorisation Testing Automation Guide; this page applies the same discipline to the agent tool-call layer.
Key takeaways
- Test the enforcement point, not the model. Authorisation belongs in a policy decision point outside the agent's context; tests target that component with deterministic inputs, so they are repeatable and fast.
- Denials matter more than allows. A suite that only proves the happy path catches broken features, not broken security. Most of your cases should assert that a call is refused.
- Delegation needs its own cases. When an agent acts for a user, the effective permission is the intersection of the agent's grant and the user's rights; test both sides of that intersection and the actor chain.
- Injected calls are a test category. Treat any tool call proposed after untrusted content entered the context as suspect, and assert that high-impact tools from that state need approval or are refused.
- Policy changes are code changes. Policies, tool manifests and scopes go through pull requests, a CI gate with coverage, and a rule that a changed high-risk policy cannot merge without updated tests.
What an agent authorisation test actually tests
An agent tool call has four parts that a policy can decide on: the principal (the agent identity, and the user it acts for when delegated), the action (the tool and operation, such as crm.read_contact or db.delete_volume), the resource (the record, repository, environment or tenant), and the context (approval state, environment, data classification, whether untrusted content is in the session, time and rate). A policy test fixes all four, asks the decision point for a decision, and compares it with the expected answer.
This framing matters because the OWASP Top 10 for LLM Applications 2025, LLM06 Excessive Agency, recommends "complete mediation": authorisation is implemented in downstream systems rather than relying on the LLM to decide whether an action is allowed. The OWASP AI Agent Security Cheat Sheet makes the same point and adds that the execution component should fail closed for unknown tools or missing approval requirements. If the only control is a system prompt telling the model not to call a tool, there is nothing deterministic to test, and the first job is to move the decision into a gateway, an MCP server or a policy engine. See the AI Agent Authorisation Guide for the architecture.
Three layers are worth testing separately:
- Policy unit tests: the policy code alone, evaluated with mocked inputs and data. Milliseconds per case, run on every commit.
- Gateway integration tests: the real tool gateway or MCP server with the real policy bundle, a stub tool backend and real tokens from a test authorisation server. These catch wiring faults: a tool that bypasses the policy hook, a token whose audience is never checked, a default that allows.
- Agent scenario tests: a full agent run against seeded content, including adversarial content, with assertions on which tool calls were attempted, which were blocked and which reached the backend.
The test case taxonomy
Build the suite from the agent permission matrix, the same way API tests are built from an authorisation matrix. Every row in the matrix produces at least one allow case and one deny case. Then add the categories that are specific to agents.
| Category | Example case | Expected result | What a failure means |
|---|---|---|---|
| Allowed call | Support agent calls tickets.read on a ticket in its own queue | Allow | Policy is too tight; feature broken |
| Denied tool | Support agent calls billing.refund, a tool not in its grant | Deny | Tool allowlist is not enforced |
| Denied resource | Agent reads a ticket in another tenant or queue | Deny | Object-level check missing (agent BOLA) |
| Denied operation on allowed tool | Agent with read scope calls the same tool with a write or delete operation | Deny | Operation not part of the decision |
| Unknown tool | Call to a tool name not in the registry, or a tool added at runtime | Deny | Default allow; registry drift |
| Environment boundary | Staging agent targets a production resource | Deny | Environment not in the policy input |
| Delegated within user rights | Agent acting for user A reads A's document | Allow | Delegation broken |
| Delegated beyond user rights | Agent acting for user A reads user B's document, which the agent's own grant would allow | Deny | Agent's standing access used instead of the user's (confused deputy) |
| Delegation chain | Sub-agent invoked by an orchestrator requests a scope the orchestrator never had | Deny | Authority not attenuated along the chain |
| High-impact without approval | payments.send or db.delete with no approval record | Deny or require approval | Human-in-the-loop bypassable |
| Approval mismatch | Approval issued for one target or amount, call made with different parameters | Deny | Approval not bound to the exact action |
| Approval replay | Same approval used twice, or after expiry | Deny | Approval not single-use or time-bound |
| Injected call | Session flagged as containing untrusted content proposes email.send to an external address | Deny or require approval | Taint context ignored by policy |
| Token audience | Token issued for a different MCP server or API presented to the tool gateway | Reject | Token passthrough accepted |
| Rate and budget | The 501st call in an hour when the limit is 500 | Deny | Quota not enforced at the gateway |
The approval cases come directly from the OWASP AI Agent Security Cheat Sheet, which says an approval should be checked against the current actor and the exact tool call, be valid and unused, be consumed atomically just before execution, and be renewed if the target or parameters change. Each of those properties is a separate deny test.
Delegation and on-behalf-of cases
Delegated calls are where agent authorisation is most often wrong, because two identities are involved and a policy that checks only one of them will pass the happy path. RFC 8693 (OAuth 2.0 Token Exchange) gives the vocabulary: in delegation the actor keeps its own identity and acts for the subject, and the act claim identifies the current actor. Nested act claims express a chain, with the outermost being the current actor and earlier actors nested more deeply; the RFC says only the top-level claims and the current actor should be used for access control, and prior actors are informational. The may_act claim states which party is allowed to become the actor.
Turn that into tests:
- Intersection: for a sample of resources, assert that the decision equals (agent may) AND (user may). Generate the cases from fixtures so that every combination of agent-allowed and user-allowed appears, including agent-allowed and user-denied, which is the case that catches confused deputy designs.
- Actor binding: present a token whose subject is user A and whose
actnames a different agent from the one calling. Expect rejection. - Chain attenuation: for orchestrator and sub-agent flows, assert that each hop's scopes are a subset of the previous hop's. A sub-agent requesting a scope that appears nowhere upstream must be refused.
- Revocation: revoke the user's grant or disable the user, then replay a delegated call. Expect denial within your stated revocation window.
The MCP security best practices for the 2025-11-25 specification state that MCP servers must not accept tokens that were not explicitly issued for them (token passthrough is forbidden) and recommend a progressive, least-privilege scope model rather than publishing every scope up front. Both are testable at the gateway layer: wrong-audience tokens and over-broad scope requests are deny cases. See Delegation Chains and Attenuated Authority for AI Agents and the Confused Deputy in AI Agents Guide.
Injected call cases
Prompt injection (OWASP LLM01; MITRE ATLAS AML.T0051 LLM Prompt Injection) is not something an authorisation policy can detect, but the policy can limit what an injected instruction can achieve. The ForcedLeak case shows why: in the ForcedLeak 2025 Agentforce prompt injection, instructions planted in a public web form led an agent handling the lead to query other CRM records and send the data out through an allowed URL. The lesson for testing is to model "untrusted content is in this session" as an input to the policy and to assert what that state permits.
- Taint flag: the gateway sets a context attribute such as
session.untrusted_input = truewhenever retrieved documents, emails, web pages or tool outputs from outside the trust boundary enter the context. Policy tests then assert that, with the flag set, external send, write and delete tools are denied or require approval, while read tools on in-scope data stay allowed. - Exfiltration paths: deny cases for every tool that can move data out: email, HTTP fetch to non-allowlisted hosts, file share links, image or link rendering to external domains. ATLAS lists this as AML.T0086 Exfiltration via AI Agent Tool Invocation.
- Destructive paths: deny or approval-required cases for delete, drop, revoke and payment tools. ATLAS lists AML.T0101 Data Destruction via AI Agent Tool Invocation.
- Scenario tests: at the agent layer, seed a document with an instruction to call a forbidden tool and assert that the gateway log shows the attempt and the denial, and that the backend stub received nothing. Do not assert that the model refused; the model is not the control.
Keep a corpus of injection seeds as test fixtures, versioned with the suite, and add every real or red-team finding to it as a regression case. The OWASP LLM Top 10 LLM01 Prompt Injection Guide and AI Red Teaming Guide cover how to build that corpus.
Writing policy tests in common engines
Most agent gateways delegate decisions to a policy engine. The three open-source engines below are listed alphabetically; each has its own way to run decisions from a test.
| Engine | Decision model | How tests are written and run | Useful CI features |
|---|---|---|---|
| Cedar | Default deny; any satisfied forbid overrides a permit; a policy that errors is skipped and reported in diagnostics | Validate policies against a schema, then evaluate principal, action, resource and context requests through the Cedar authoriser from your test framework and assert Allow or Deny plus the determining policies | Schema validation catches unknown entity types, actions and attributes, unguarded optional attributes and type mismatches before deployment |
| Open Policy Agent (Rego) | Rules you define; tests are Rego rules prefixed test_ | opa test runs every test_ rule; the with keyword replaces input, data or functions for one evaluation | --coverage reports evaluated lines; --fail-on-empty fails when no tests run; --format=json for machine-readable results |
| OpenFGA | Relationship-based (ReBAC) model plus relationship tuples, with optional conditions | A .fga.yaml file holds the model, tuples and tests with check, list_objects and list_users assertions; run with fga model test --tests | A model testing GitHub Action runs the file in a workflow; per-test tuples isolate cases |
Whatever the engine, three habits make the suite reliable:
- Assert the reason, not just the result. A deny that comes from the default rule when you expected a specific
forbidis a hidden fault. Cedar's diagnostics list determining policies; in Rego, return a reason set alongsideallow. - Test errors explicitly. Cedar skips a policy that errors rather than denying, so a broken
forbidsilently stops protecting. Add a test that feeds a request missing an optional attribute and asserts the forbid still applies or that the gateway fails closed. - Fail on empty. A test runner that finds no tests and exits successfully is a common way for a suite to disappear after a refactor. Use
--fail-on-emptyin OPA and an equivalent count check elsewhere.
For OPA in production, see Open Policy Agent in Production. For choosing between models, see the Authorisation Models Guide.
Building it into the pipeline
Agent authorisation lives in more files than a normal API: policy code, the tool registry or manifest, MCP server configuration, OAuth client scope definitions, approval rules and the permission matrix itself. Put all of them in version control and trigger the suite on a change to any of them.
- Inventory and matrix first. List every agent, its tools, operations, resource scopes and delegation mode. This becomes the test oracle. The AI Agent Permission Matrix Template is a starting point.
- Policy unit tests on every commit. Generate allow and deny cases from the matrix; hand-write the delegation, approval and taint cases. Gate merges on pass and on a coverage floor for policy files.
- Change rules for high-risk policy. Use code owners so that changes to policies covering destructive, financial, administrative or external-send tools need security review, and add a CI check that fails when those policy files change without a change in the matching test files. The OWASP cheat sheet recommends blocking releases when high-risk policies change without updated tests, and protecting the tests themselves, because the same change can weaken both.
- Gateway integration tests on merge. Deploy the policy bundle and gateway to an ephemeral environment with a stub backend and a test authorisation server. Run token audience, scope, revocation and unknown-tool cases against the real wiring.
- Agent scenario tests nightly and before release. Run the injection corpus and delegation scenarios against the full agent. Record which calls were attempted, decided and executed.
- Shadow evaluation before enforcement. When rolling out a new or tightened policy, run it in log-only mode alongside the current policy in production, compare decisions for a week, review every difference, then switch.
- Rollback. Policy bundles are versioned artefacts. Keep the previous signed bundle deployable with one change, and test the rollback path in staging. Never roll back by switching the gateway to allow-all.
Keep evidence of the bundle version, cases run, denials observed and accepted risk, as the OWASP cheat sheet recommends. See the CI/CD Security Guide for protecting the pipeline that runs these gates.
Decision guidance: how far to go
| Situation | Minimum suite | Add when |
|---|---|---|
| One internal agent, read-only tools | Allow and deny per tool, unknown tool, wrong audience token | The first write tool or the first user-delegated call appears |
| Agents acting for users (copilots, assistants) | Above plus the delegation intersection, actor binding and revocation | Agents start calling other agents |
| Agents with destructive or financial tools | Above plus approval binding, replay, expiry and taint cases, with code-owner review on those policies | Always for these tools |
| Multi-agent orchestration, many teams | Above plus chain attenuation and generated matrix cases, shadow evaluation for every policy change | Policy is shared across teams or tenants |
Small teams can start with a few dozen hand-written cases; large organisations need generated cases, shared test helpers and a named owner for each agent's matrix.
Detection and measurement
Tests prove the policy before release; production telemetry proves it in use. Log every decision at the gateway with the agent identity, the delegated user, the actor chain, the tool, operation, resource, context flags, decision, determining policy and policy bundle version. See the AI Agent Audit Log Schema Template.
- Deny ratio by agent and tool: a sudden rise suggests injection or a broken release; a fall to zero for a tool that used to see denials suggests the policy has been loosened.
- Policy coverage: share of policy lines or rules exercised by the suite; aim for full coverage of rules on high-risk tools.
- Matrix coverage: share of matrix rows with both an allow and a deny test.
- Production decisions not seen in tests: distinct (agent, tool, operation, decision) tuples in production logs with no matching test case; each one is a missing test.
- Time from finding to regression test: days between a red-team or incident finding and a merged test that would catch it.
- Shadow diff rate: share of decisions that differ between the enforced and candidate policies before a switch.
Common failure patterns
- Testing the prompt instead of the policy: scenario tests that pass because the model happened to refuse. When the model or prompt changes, the protection disappears. Assert on gateway decisions only.
- Over-broad credentials outside the policy path: the PocketOS database deletion happened when a coding agent found an account-scoped API token in a file and used it to delete a production volume and its backups. No tool-call policy is tested if the agent can reach a credential that bypasses the gateway; include a test environment check that agent runtimes cannot read stray tokens, and see Runtime Secrets Injection for AI Agents Without Prompt Exposure.
- Default allow for new tools: a tool registered at runtime or added to an MCP server is callable until someone writes a rule. The unknown-tool deny case catches this.
- Checking only the agent in delegated calls: the agent's standing grant covers everything the user might need, so cross-user access passes. The intersection tests catch this.
- Approvals not bound to parameters: a human approves "refund order 123" and the agent executes a refund on a different order with the same approval token.
- Silent suite loss: a moved directory or renamed package leaves the runner with nothing to run and a green build.
Framework mapping
| Framework | Reference | How this guide applies it |
|---|---|---|
| NIST CSF 2.0 | PR.AA-05; PR.PS-06; ID.IM-02 | Permissions defined in policy and enforced; secure development practice integrated in the pipeline; improvements from tests and exercises |
| NIST SP 800-53 Rev. 5 | AC-3 Access Enforcement; AC-6 Least Privilege; SA-11 Developer Testing and Evaluation; CM-3 Configuration Change Control; CM-4 Impact Analyses; AU-12 Audit Record Generation | Policy decision point, scoped tools, CI tests, reviewed policy changes, shadow evaluation, decision logs |
| OWASP ASVS 5.0 | V8.1.1; V8.2.1; V8.2.2; V8.3.1 | Documented rules, function-level and data-level checks, enforcement at a trusted service layer |
| OWASP Top 10 for LLM Applications 2025 | LLM06 Excessive Agency; LLM01 Prompt Injection | Complete mediation and user approval; injected call cases |
| MITRE ATLAS | AML.T0053 AI Agent Tool Invocation; AML.T0086 Exfiltration via AI Agent Tool Invocation; AML.T0101 Data Destruction via AI Agent Tool Invocation | Deny and approval cases for the tool calls these techniques abuse |
| ISO/IEC 27001:2022 Annex A | A.8.29 Security testing in development and acceptance | Policy tests as an acceptance gate |
Practitioner checklist
- Move every tool-call decision into a gateway, MCP server or policy engine that fails closed, and remove reliance on prompt instructions.
- Build the agent permission matrix and generate one allow and one deny case per row.
- Add deny cases for unknown tools, wrong environments, wrong-audience tokens and operations beyond scope.
- Test delegated calls as the intersection of agent and user rights, plus actor binding, chain attenuation and revocation.
- Bind approvals to actor, tool, target, parameters and expiry, and test mismatch and replay.
- Model untrusted content as a policy input and assert what high-impact tools do when it is set.
- Run policy tests on every commit with coverage and fail-on-empty; gateway tests on merge; scenario tests nightly.
- Require code-owner review and matching test changes for policies on destructive, financial or external-send tools.
- Shadow-evaluate tightened policies in production before enforcing, and keep the previous bundle ready for rollback.
- Log every decision with the policy version and turn each unseen production tuple into a test.
Standards and references
- OWASP: Top 10 for LLM Applications 2025 (LLM06 Excessive Agency)
- OWASP: AI Agent Security Cheat Sheet
- OWASP: Application Security Verification Standard 5.0
- IETF: RFC 8693 OAuth 2.0 Token Exchange
- Model Context Protocol: Security Best Practices
- MITRE ATLAS: AI Agent Tool Invocation
- Open Policy Agent: Policy Testing
- Cedar: Authorization
Related NHI Mgmt Group resources: Authorisation Testing Automation Guide · AI Agent Authorisation Guide · AI Agent Security Testing Checklist · OWASP LLM Top 10 LLM06 Excessive Agency Guide · Agent Controls and Monitoring Guide