|
4 | 4 |
|
5 | 5 | # CPEX |
6 | 6 |
|
7 | | -<i>A policy and authorization framework for agentic applications.</i> |
| 7 | +<i>A policy enforcement runtime for AI agents.</i> |
8 | 8 |
|
9 | 9 | [](https://github.com/contextforge-org/cpex/actions/workflows/ci.yml) |
10 | 10 | [](LICENSE) |
|
17 | 17 |
|
18 | 18 | ## What's CPEX? |
19 | 19 |
|
20 | | -CPEX is a deterministic reference monitor between an untrusted agent and the capabilities it invokes. |
| 20 | +CPEX is a policy enforcement runtime for AI agents. |
21 | 21 |
|
22 | | -AI agents can be steered by injected content, confused by tool output, or simply make mistakes. CPEX mediates every operation an agent triggers (tool calls, A2A methods, inference calls, prompt and resource fetches) against state the agent cannot see or forge: identity, delegation chains, taint labels, and an append-only audit log. |
| 22 | +It acts as a deterministic reference monitor between an agent and every capability it invokes: tools, prompts, resources, inference providers, and A2A methods. Every operation is evaluated against security state the model cannot observe or influence—identity, delegation chains, information-flow labels, and an append-only audit log. |
| 23 | + |
| 24 | +Instead of scattering authorization, delegation, redaction, auditing, and information-flow controls across application code, CPEX executes them as a single policy-defined pipeline. Identity can be resolved, an external PDP consulted, credentials exchanged, inputs or outputs transformed, session state updated, and the operation audited—all within one deterministic flow. |
23 | 25 |
|
24 | 26 | <div> |
25 | 27 | <img alt="CPEX mediates every operation an untrusted LLM triggers, evaluating APL policy against identity, delegation, taint, and audit state the model cannot forge" src="https://github.com/contextforge-org/cpex/blob/main/docs/static/images/cpex_overview.png?raw=true" /> |
26 | 28 | </div> |
27 | 29 |
|
28 | | -You write policy in APL (Authorization Policy Language): declarative, attribute-based rules with explicit effects. CPEX evaluates that policy at the boundary and enforces the result, allowing, denying, redacting, delegating, or tainting before the operation proceeds. |
| 30 | +## Policy lives on the entity |
| 31 | + |
| 32 | +APL is a declarative policy language designed around capabilities rather than requests. |
| 33 | + |
| 34 | +Every entity an agent can invoke—a tool, resource, prompt, or A2A method—owns its own policy. Each policy executes in two phases: before invocation and after the result. Most policies fit comfortably on a single screen. |
29 | 35 |
|
30 | | -## Same request, different data |
| 36 | +A route identifies an entity and defines the enforcement pipeline. Predicates decide whether execution may continue (`require`). PDPs evaluate external authorization (`cel`, `cedar`, or custom resolvers). Effects perform enforcement (`delegate`, `redact`, `taint`, `run`). Steps execute deterministically, in order, with only the context they explicitly declare. |
31 | 37 |
|
32 | | -Three callers issue the identical `get_compensation` request. The backend returns the same record. What each receives differs, because policy decides per identity. |
| 38 | +## End-to-end enforcement, multiple security contexts |
| 39 | + |
| 40 | +The example below places CPEX between a single agent and three backends: HR records, source repositories, and email. The agent remains unchanged. Policy adapts each operation to the caller's identity, permissions, and session state. |
| 41 | + |
| 42 | +<div> |
| 43 | + <img alt="One agent serves three users across HR, repo, and email backends; CPEX policy produces a different outcome per identity" src="https://github.com/contextforge-org/cpex/blob/main/docs/static/images/demo_scenario.png?raw=true" /> |
| 44 | +</div> |
| 45 | + |
| 46 | +One policy defines three distinct enforcement pipelines, one for each entity. |
33 | 47 |
|
34 | 48 | ```yaml |
35 | 49 | routes: |
| 50 | + # HR lookup: gate on role, scope a downstream token, redact by permission, taint the session. |
36 | 51 | - tool: get_compensation |
37 | 52 | policy: |
38 | 53 | - "require(role.hr)" |
| 54 | + - "delegate(workday-oauth, target: workday-api, permissions: [read_compensation])" |
| 55 | + - "taint(secret, session)" |
| 56 | + - "run(audit-log)" |
39 | 57 | result: |
40 | 58 | ssn: "str | redact(!perm.view_ssn)" |
| 59 | + |
| 60 | + # Repo search: gate on team, decide with CEL (or Cedar), require the scoped grant. |
| 61 | + - tool: search_repos |
| 62 | + policy: |
| 63 | + - "require(team.engineering | team.security)" |
| 64 | + - cel: |
| 65 | + expr: "(role.engineer && args.visibility == 'internal') || role.security" |
| 66 | + on_deny: ["deny('engineers read internal only; security reads any', 'cel.policy_denied')"] |
| 67 | + - "delegate(github-oauth, target: github-api, permissions: [repo:read:internal])" |
| 68 | + - "run(audit-log)" |
| 69 | + |
| 70 | + # Outbound email: refuse if the session already touched secret data. |
| 71 | + - tool: send_email |
| 72 | + policy: |
| 73 | + - "require(perm.email_send)" |
| 74 | + - "run(pii-scan)" |
| 75 | + - "security.labels contains \"secret\": deny('write-down blocked', 'session_tainted')" |
| 76 | + - "run(audit-log)" |
41 | 77 | ``` |
42 | 78 |
|
43 | | -- An HR analyst with `view_ssn` gets the full record. |
44 | | -- An HR analyst without `view_ssn` gets the record with the SSN redacted before it leaves CPEX. The backend never sees the difference. |
45 | | -- An engineer is denied at `require(role.hr)`. The call never reaches the backend. |
| 79 | +Two examples illustrate the behavior: |
46 | 80 |
|
47 | | -No application code changed between the three outcomes. The policy did. |
| 81 | +- **Same request, different result.** An HR analyst with `view_ssn` receives the full record. Without that permission, the SSN is redacted before the response leaves CPEX. Engineers never reach the backend because the request is rejected by `require(role.hr)`. |
48 | 82 |
|
49 | | -## What you can express |
| 83 | +- **Information follows the session.** Reading compensation data taints the session. Later attempts to send external email are blocked—even if the email itself contains no sensitive content. |
50 | 84 |
|
51 | | -APL composes the controls an agent stack needs, evaluated against identity claims, relationships, roles, and attributes (ReBAC, RBAC, ABAC). A few sketches: |
| 85 | +The application stays the same. Only the policy changes. |
52 | 86 |
|
53 | | -**Authorization** on both request inputs and response outputs, for tools, resources, prompts, A2A methods, and other agent interfaces: |
| 87 | +## Beyond request-level authorization |
54 | 88 |
|
55 | | -```yaml |
56 | | -policy: |
57 | | - - "require(role.hr | role.security)" |
58 | | -args: |
59 | | - region: "enum(us, eu, apac)" # validate inputs |
60 | | -result: |
61 | | - salary: "int | redact(!perm.view_comp)" # redact outputs by permission |
62 | | -``` |
| 89 | +RBAC, ABAC, Cedar, OPA, AuthZEN, and similar systems answer an important question: |
63 | 90 |
|
64 | | -**PDP composition**: gate with your preferred policy engine (CEL and Cedar ship as builtins; OPA, AuthZEN, and NeMo are recognized dialects you wire to a host resolver): |
| 91 | +> Should this request be allowed? |
65 | 92 |
|
66 | | -```yaml |
67 | | -policy: |
68 | | - - cel: |
69 | | - expr: "subject.department == 'compliance' || 'admin' in subject.roles" |
70 | | - on_deny: |
71 | | - - "deny('not permitted by policy', 'pdp_denied')" |
72 | | -``` |
| 93 | +CPEX answers a broader one: |
73 | 94 |
|
74 | | -**Delegation** as an explicit effect: RFC 8693 token exchange that scopes and reduces privilege before downstream calls, verified after the exchange: |
| 95 | +> What security pipeline should execute for this agent operation? |
75 | 96 |
|
76 | | -```yaml |
77 | | -policy: |
78 | | - - "delegate(workday-oauth, target: workday-api, permissions: [read_compensation])" |
79 | | - - "delegation.granted.permissions contains 'read_compensation': allow" |
80 | | -``` |
| 97 | +That pipeline can combine request authorization with credential delegation, response transformation, information-flow tracking, auditing, and session state into a single deterministic policy. |
81 | 98 |
|
82 | | -**Information-flow control**: session tainting that detects and blocks write-down, for example refusing an external send after the session touched secret data: |
| 99 | +Three capabilities distinguish this model: |
83 | 100 |
|
84 | | -```yaml |
85 | | -# get_compensation taints the session |
86 | | -policy: ["require(role.hr)", "taint(secret, session)"] |
87 | | -# send_email, later in the same session, refuses even with a clean body |
88 | | -policy: |
89 | | - - "require(perm.email_send)" |
90 | | - - "security.labels contains \"secret\": deny('write-down blocked', 'session_tainted')" |
91 | | -``` |
| 101 | +- **Information flow across operations.** Policy can carry security state across an entire agent session, preventing write-down and other cross-call attacks rather than evaluating each request in isolation. |
| 102 | + |
| 103 | +- **Delegation as policy.** OAuth token exchange (RFC 8693), capability reduction, and downstream credential verification become ordinary policy steps instead of bespoke integration code. |
92 | 104 |
|
93 | | -The pipeline underneath (hooks, the plugin manager, execution modes) is the mechanism that runs policy effects. It is the supporting layer. APL is how you express intent; the pipeline is how that intent executes. Plugins are capability-gated, so an effect only sees the context it declares. |
| 105 | +- **Decision orchestration.** Existing authorization systems remain the source of truth. APL invokes Cedar, CEL, OPA, AuthZEN, or custom resolvers wherever a decision is needed, while CPEX enforces the resulting security pipeline. |
94 | 106 |
|
95 | 107 | ## Where it runs |
96 | 108 |
|
97 | | -CPEX is direction-agnostic. The same policy enforces whether CPEX sits in front of a tool server as a gateway, beside an agent as an egress sidecar, or inside an agent framework. Move the enforcement point; keep the policy. |
| 109 | +CPEX enforces policy wherever an agent crosses a trust boundary. |
| 110 | + |
| 111 | +It can run in front of tool servers, beside an agent as an egress sidecar, inside an agent framework, or as middleware between components. The enforcement point can move without changing policy, allowing the same APL configuration to span gateways, agents, and services. |
98 | 112 |
|
99 | 113 | ## Install |
100 | 114 |
|
@@ -162,7 +176,9 @@ See [CONTRIBUTING.md](CONTRIBUTING.md) for the full workflow and [SECURITY.md](S |
162 | 176 |
|
163 | 177 | ## Project Status |
164 | 178 |
|
165 | | -CPEX is under active development as part of the [ContextForge](https://github.com/contextforge-org) ecosystem. It is designed to work across AI gateways, agent frameworks, LLM proxies, and tool servers. |
| 179 | +CPEX is under active development as part of the ContextForge ecosystem. |
| 180 | + |
| 181 | +The project is designed as a reusable enforcement layer for agentic systems, integrating with AI gateways, agent frameworks, LLM proxies, MCP servers, and other capability providers through a common policy model. |
166 | 182 |
|
167 | 183 | ## License |
168 | 184 |
|
|
0 commit comments