AI Multi-Agent Permission Delegation with Cedar: The delegation_chain Pattern, a Production Policy Library, and Security Pitfalls
As AI agent systems evolve from single models to orchestrator-subagent architectures, one area collapses quietly yet fastest: delegation. The implicit assumption that "if the orchestrator is permitted, the subagent should be fine too" can bring down an entire security boundary. It is no coincidence that Excessive Agency and Identity & Permission Misuse (ASI03) rank among the top risks in OWASP Agentic Top 10 (2026).
This article covers the delegation_chain pattern — an approach to explicitly designing inter-agent permission delegation using Cedar, the open-source policy language developed by AWS. After reading this, you will be able to implement the Cedar delegation_chain pattern yourself, design a 3-layer policy library, and identify 8 common security pitfalls in orchestrator-subagent architectures. We will explore how to structure a policy library, what security pitfalls lurk within it, and production-ready code you can apply immediately.
The target audience is backend and cloud developers designing or operating LLM-based multi-agent systems. If you have an interest in IAM or authorization systems, you can follow along from concepts to production code even if you are new to Cedar. Advanced topics such as SPIFFE/SVID and MCP servers are explained with background context in each section, with links to further reading where needed.
Core Concepts
Cedar Policy Language: Policies as Data, Not Code
Cedar is a policy language that declares permissions using a 3-tuple structure of principal → action → resource. It has three defining characteristics.
- RBAC·ABAC·ReBAC unified: Role-based, attribute-based, and relationship-based policies are expressed in a single language.
- Entity hierarchy (DAG): Entities form a Directed Acyclic Graph, enabling declarative parent-child permission inheritance. For example, an
Organization → Team → Agenthierarchy can be modeled as a DAG. - Static analyzability: "Actions this policy will never permit" can be mathematically proven at compile time, which is advantageous for auditing.
// Basic permit structure: alice can read documents in the engineering-docs folder
permit(
principal == User::"alice",
action == Action::"ReadDocument",
resource in Folder::"engineering-docs"
);Cedar vs. Rego (OPA): Rego is a Turing-complete language with high expressiveness but difficult static analysis. Cedar intentionally limits expressiveness so that "what this policy permits" can be proven automatically, and is designed to guarantee an upper bound on evaluation latency for real-time authorization.
The delegation_chain Pattern: Modeling Delegation as First-Class Data
delegation_chain is not an official Cedar documentation pattern name; it is a design pattern that solidified through the OpenClaw framework and community practice. It refers to the approach of modeling the delegation itself — when an orchestrator delegates permissions to a subagent — as additional entity data attached to the context of a Cedar request.
The core principles are as follows.
- Subagents do not automatically inherit parent permissions.
- Delegation does not grant standing permissions; it constrains the space in which an agent can act.
- Keep the policy set stable and adjust only the delegation scope dynamically (Delegation as Data).
Orchestrator
│
▼ Generate and sign delegation data (HMAC / JWT)
Sub-agent-1
│
▼ Attach context.delegation → Send authorization request to Cedar PEP
Policy Enforcement Point (PEP) ← Intercepts before every tool call
│
▼ Cedar evaluation service
Allow / DenyPolicy Enforcement Point (PEP): A component that intercepts authorization requests to the Cedar evaluation service before an agent invokes a tool or executes an external action. It implements the principle that permission-checking logic must not live inside agent code.
3-Layer Structure Strategy for a Production Policy Library
When structuring a policy library, it is recommended to divide it into three layers.
| Layer | Role | Update Frequency |
|---|---|---|
| Base Policy | Absolute allow/deny rules (e.g., prohibit writes to production DB) | Low |
| Role Policy | Permission sets per agent type | Medium |
| Delegation Policy | Dynamic delegation scope, expiration, and conditions for specific tasks | High |
Manage base and role policies statically under version control, and only create and revoke delegation policies at runtime. This suppresses the policy explosion problem while maintaining flexibility.
Practical Application
Example 1: OpenClaw-style delegation_chain Delegation Policy
A scenario where an orchestrator delegates only read access to a project documentation folder to a subagent.
// Orchestrator allows the subagent to read files only
// context.requestTime must be populated by the PEP with the current time (ISO 8601)
permit(
principal == Agent::"sub-agent-1",
action == Action::"ReadFile",
resource in Folder::"project-docs"
) when {
context.delegation.grantedBy == "Agent::orchestrator" &&
context.delegation.scope == "read-only" &&
datetime(context.delegation.expiresAt) > datetime(context.requestTime)
};
// WriteFile is always denied even if another permit exists
forbid(
principal == Agent::"sub-agent-1",
action == Action::"WriteFile",
resource in Folder::"project-docs"
);
context.nowis not provided by Cedar by default. You must use Cedar'sdatetime()extension function for expiration time comparison, and the PEP must explicitly populatecontext.requestTimewith the current time in ISO 8601 format at the moment of the authorization request. Omitting this will cause a runtime error.
| Syntax Element | Role |
|---|---|
context.delegation.grantedBy |
Validates the delegation issuer. Explicitly verifies the orchestrator's identity |
context.delegation.scope |
Restricts the allowed scope to a string. Vulnerable to typos and case differences — in production, it is recommended to define this as an enumerated attribute in the Cedar schema |
datetime(context.delegation.expiresAt) |
Expiration time comparison. Implements the time-based principle of least privilege |
forbid clause |
Explicit denial. In Cedar, when both permit and forbid match, forbid always takes precedence |
Delegation data (context.delegation) is signed by the orchestrator using HMAC or JWT, verified by the PEP, and then passed to the Cedar evaluation service. Even if a subagent requests WriteFile permission, it is immediately denied by the forbid clause.
Example 2: Amazon Bedrock AgentCore Policy — Restricting Payment Tool Access
To use a custom entity type like AgentSession, it must first be declared in a .cedarschema file. This is an example of controlling payment tool usage in an agent session within Bedrock AgentCore (GA March 2026) using amount and approval level conditions.
// Excerpt from .cedarschema file — AgentSession entity type definition
{
"entityTypes": {
"AgentSession": {
"shape": {
"type": "Record",
"attributes": {
"approvalLevel": { "type": "Long", "required": true },
"tenantId": { "type": "String", "required": true }
}
}
},
"Tool": {}
},
"actions": {
"InvokePaymentTool": {
"appliesTo": {
"principalTypes": ["AgentSession"],
"resourceTypes": ["Tool"]
}
}
}
}// Always deny payment tool invocations unless conditions are met
// unless { condition } = when { !condition }, a common Cedar idiom
forbid(
principal is AgentSession,
action == Action::"InvokePaymentTool",
resource is Tool
) unless {
principal.approvalLevel >= 2 && // Approval level 2 or higher
context.requestedAmount <= 1000 // Requested amount 1000 or less
};Cedar's
forbid ... unlesspattern: Well-suited for enforcing specific conditions when there is a broadpermitin the base policy. When the condition is met, theforbiddoes not trigger and the basepermitapplies; when the condition is not met, theforbidtakes precedence and overrides the basepermit. If there is no basepermit, a singlepermit when { condition }policy produces the same effect.
This policy is applied externally without modifying agent code. Bedrock AgentCore Policy also offers a feature to convert natural language rules into Cedar, enabling non-developer team members to participate in policy review.
Example 3: Minimizing Permission Scope per MCP Server
MCP (Model Context Protocol) is a protocol that connects agents to external tools. By applying separate Cedar policies per MCP server, you can configure agents to access only the tools they need.
// Code agent MCP server: allow GitHub reads only
permit(
principal == MCPServer::"code-agent-mcp",
action in [Action::"GitHubRead", Action::"ListRepos"],
resource is GitHubRepository
) when {
context.mcpServer.verified == true
};
// Deploy agent MCP server: grant write access only when approved
permit(
principal == MCPServer::"deploy-agent-mcp",
action in [Action::"GitHubWrite", Action::"CreateRelease"],
resource is GitHubRepository
) when {
context.mcpServer.verified == true &&
context.environment == "production" &&
context.deployApproved == true
};| Agent | MCP Server | Allowed Actions |
|---|---|---|
| Code agent | code-agent-mcp |
GitHubRead, ListRepos |
| Deploy agent | deploy-agent-mcp |
GitHubWrite, CreateRelease (when approved) |
It is recommended to integrate each MCP server's identity with SVIDs (SPIFFE Verifiable Identity Documents) issued by SPIFFE/SPIRE. When the PEP cryptographically verifies the SVID's SPIFFE ID (e.g., spiffe://example.org/agent/code-agent) and maps it to the context.mcpServer.spiffeId attribute in the Cedar context, agent identity can be guaranteed without any code changes.
SPIFFE/SVID: An open-source standard that automatically issues short-lived cryptographic identity documents (SVIDs) to workloads (servers, containers, agent processes). It enables service-to-service identity proof without long-lived credentials (API keys, passwords).
Example 4: SaaS Multi-Tenant Isolation — Using Entity Hierarchies
An approach to declaring tenant isolation as policy using Cedar's entity DAG.
// Agents can only access resources belonging to their own tenant
permit(
principal is Agent,
action == Action::"AccessResource",
resource is TenantResource
) when {
principal.tenantId == resource.tenantId // Allowed only when tenant IDs match
};Entity data (JSON) is managed separately from policies. Below is the actual entity data format expected by Cedar.
[
{
"uid": { "type": "Organization", "id": "acme" },
"attrs": { "tenantId": "acme" },
"parents": []
},
{
"uid": { "type": "Team", "id": "backend" },
"attrs": {},
"parents": [{ "type": "Organization", "id": "acme" }]
},
{
"uid": { "type": "Agent", "id": "agent-42" },
"attrs": { "tenantId": "acme" },
"parents": [{ "type": "Team", "id": "backend" }]
},
{
"uid": { "type": "TenantResource", "id": "acme-db" },
"attrs": { "tenantId": "acme" },
"parents": []
}
]When adding a new tenant, you only need to register entity data without changing any policy code. You can immediately verify evaluation results locally using the Cedar CLI.
# Checking authorization evaluation results using the Cedar CLI
cedar authorize \
--policies policy.cedar \
--entities entities.json \
--principal 'Agent::"agent-42"' \
--action 'Action::"AccessResource"' \
--resource 'TenantResource::"acme-db"' \
--context '{"requestTime": "2026-04-17T10:00:00Z"}'
# Result: ALLOWPros and Cons Analysis
Advantages
| Item | Description |
|---|---|
| Analyzability | Actions that the policy will never permit can be mathematically proven at compile time |
| Code-policy separation | Agent business logic and permission policies are separated, making audit trails clear |
| Dynamic delegation control | Modeling delegation as data allows scope, expiration, and conditions to be flexibly changed at runtime |
| RBAC+ABAC unified | Role-based and attribute-based policies are expressed together in a single language |
| Fast evaluation | Designed to guarantee an upper bound on evaluation latency, suitable for real-time authorization scenarios |
| Managed service integration | Native integration with Amazon Verified Permissions and Bedrock AgentCore Policy |
Disadvantages and Caveats
| Item | Description | Mitigation |
|---|---|---|
| Excessive privilege propagation | An orchestrator's excessive permissions spread across the entire delegation chain; blast radius multiplies by the number of agents | Apply the principle of least privilege to orchestrators as well, and pass only a subset of parent permissions when delegating |
| Confused Deputy attack | A high-privilege agent is manipulated via prompt injection to perform privileged actions on behalf of a low-privilege requester by tampering with the delegation context | Do not trust delegation data at the PEP blindly; only accept delegation tokens signed by the orchestrator |
| Delegation data tampering | If an agent constructs context.delegation directly, forgery is possible without signature or integrity verification |
Sign delegation data with HMAC or JWT and verify at the PEP |
| Context blind spots | Authorization context conveyed via natural language prompts cannot be evaluated by Cedar | Do not trust context that is not enforced by policy as a security boundary |
| Scope creep | A tendency to grant broad static permissions to prevent task failures | Apply delegation expiration (expiresAt) together with the principle of least privilege |
| Unclear identity attribution | In multi-agent environments, accountability for "who performed this action" becomes ambiguous | Issue independent identities for each orchestrator, subagent, and tool using SPIFFE/SPIRE |
| Policy explosion | As the number of agents grows, the number of policies grows linearly | Use policy templates and group entities (e.g., AgentGroup) to control management complexity |
| Lack of standards | Standard protocols for inter-agent delegation proof are still immature | Reference implementations like the OpenClaw demo, and add your own verification layer |
Confused Deputy attack: A security vulnerability in which a privileged service (the Deputy) unintentionally performs privileged actions on behalf of an unprivileged requester. In AI agent environments, prompt injection is a representative attack vector.
blast radius: The scope of impact when a security incident occurs. If an orchestrator holds excessive permissions, the potential damage extends by the number of subagents beneath it.
Most Common Mistakes in Production
-
Not signing delegation data: If the system is designed so that subagents can arbitrarily construct
context.delegation, a single prompt injection can contaminate the entire delegation chain. It is strongly recommended to ensure that delegation tokens are always signed by the orchestrator and verified by the PEP. -
Delegating without an expiration time: If delegation remains alive after a task completes, it leaves an unnecessary attack surface. Set a maximum validity period for all delegations and establish a flow to immediately revoke them upon task completion. Going one step further, enforcing an absolute upper limit (e.g., maximum 15 minutes) via
forbidin the base policy layer acts as a safety net even if a delegation policy accidentally sets a long expiration. -
Trusting natural language prompts as authorization evidence: Even if a prompt states that "this agent was approved by an administrator," it is not an effective security boundary unless reflected in Cedar policy. All permission decisions must be made solely based on Cedar policies and entity data.
Closing Thoughts
Through this article, we explored how to explicitly design orchestrator-subagent delegation using the Cedar delegation_chain pattern, control operational complexity with a 3-layer policy library, and identify 8 common security pitfalls in production. Separating agent business logic from permission boundaries to create an auditable, analyzable authorization system — that is the starting point of multi-agent system security.
Three steps you can start with right now:
- Learn the basic syntax in the Cedar Playground: At Cedar Playground, you can write
permit/forbidpolicies and immediately check evaluation results together with entity data. If you want to get started in a local Rust environment, try adding the crate withcargo add cedar-policy. - Run the OpenClaw delegation demo: Clone the
openclaw-cedar-policy-demorepository and followdemo/README-delegation.mdto run the delegation chain example locally, so you can see thecontext.delegationstructure and PEP flow firsthand. - Apply a PEP layer to an existing agent system: Using Amazon Bedrock AgentCore Policy (AWS Console → Bedrock → AgentCore), you can experience controlling tool access via external Cedar policies without modifying any agent code.
Next article: A practical guide to issuing AI agent workload identities (SVIDs) with SPIFFE/SPIRE and combining them with Cedar to build a Zero Trust agent authentication pipeline
References
Good resources to get started
- Cedar Policy Language Reference Guide | Official Documentation
- Cedar Design Patterns | Official Documentation
- Best Practices of Authorizing AI Agents | OSO
- Setting Permissions for AI Agents | OSO
- OWASP Top 10 for Agentic Applications 2026 | OWASP
- openclaw-cedar-policy-demo README-delegation.md | GitHub
- Amazon Verified Permissions | AWS Documentation
Advanced resources
- Delegation as Data: Applying Cedar Policies to OpenClaw Subagents | windley.com
- A Policy-Aware Agent Loop with Cedar and OpenClaw | windley.com
- Controlling Agent Tool Access with Bedrock AgentCore Policy and Cedar Authorization | shinyaz.com
- AWS Ships Agent Governance: Bedrock AgentCore Policy Goes GA | OpenClawAI
- Understanding Cedar policies — Amazon Bedrock AgentCore | AWS Documentation
- Cedar: A New Language for Expressive, Fast, Safe, and Analyzable Authorization | ACM
- Nobody Authorized That Agent | Medium
- AI Agent Orchestration Security | Wiz
- The Looming Authorization Crisis: Why Traditional IAM Fails Agentic AI | ISACA
- SPIFFE: Securing the Identity of Agentic AI | HashiCorp
- MCP Security: TOP 25 MCP Vulnerabilities | Adversa AI
- Cedar for Kubernetes | CNCF Blog
- Benchmarking Policy Engines: Rego, Cedar, OpenFGA | Teleport