Skip to content

[FEATURE]: Attribute Policy Language with Explicit Effects #14

@terylt

Description

@terylt

Summary

APL is an attribute policy language purpose-built for AI agent systems. It provides a declarative way to evaluate attributes such as identity, permissions, session state, delegation context, metadata, and content, then apply explicit effects such as allow, deny, taint, transform, redact, mask, invoke plugins, or call external policy engines.

APL also includes sequencing and orchestration semantics, allowing policy actions to run in ordered pipelines, conditionally, or in parallel where appropriate. This enables policies that do more than authorize requests. They can coordinate multi-step enforcement workflows across the full agent execution lifecycle.

Through these capabilities, APL controls what agents can see, do, and share, with identity-aware access control, field-level data transforms, session taint tracking, token delegation, and composable integration with existing policy engines such as OPA, Cedar, AuthZEN, and NeMo Guardrails.

APL is built on CMF (Contextual Message Format) and runs inside CPEX (ContextForge Plugin Extensibility Framework), but the policy language itself is independent. It evaluates attributes and produces effects that any host can enforce.

APL Specification

The Problem

Enterprises deploying AI agents face a class of security challenges that traditional API security wasn't designed for:

Over-privileged tool access — An agent calling an HR API gets the full record, including fields the end user should never see. There's no field-level filtering based on who the user is or what role they hold.

No data flow control — Once an agent reads sensitive data, nothing prevents it from passing that data to another tool, writing it to a log, or including it in an email. PII leaks aren't from breaches — they're from normal agent workflows.

Identity confusion — The agent authenticates to the gateway, but the user's identity and permissions are lost by the time a tool is called. Policy decisions are made against the agent's credentials, not the human's.

Delegation without narrowing — When an agent calls a downstream service on behalf of a user, it forwards its own broad token. There's no standard way to mint a scoped, short-lived credential for just that one operation.

No session awareness — Each tool call is evaluated in isolation. The system has no memory that the agent already accessed PII two calls ago, and no way to restrict what happens next based on that history.

Policy fragmentation — Organizations use different policy engines for different concerns (OPA for authorization, NeMo for content safety, Cedar for fine-grained access). There's no way to compose them in a single evaluation pipeline over a common data model.

What APL Does

APL is a predicate-and-effects language. Every rule consists of a predicate evaluated against the current execution context, and one or more effects that execute when the predicate matches.

Organizes policy around agentic entities

Tools, prompts, resources, and LLMs are first-class objects with routes, conditions, and field-level transforms:

global:
  policies:
    all:
      description: "Baseline authentication requirement"
      policy:
        - require(authenticated)
    pii:
      description: "PII data access controls"
      metadata:
        owner: security-team
        severity: high
      policy:
        - require(perm.pii_access)
      post_policy:
        - exists(result.ssn): taint(PII, session)

routes:
  - tool: get_compensation
    meta:
      tags: [pii]
    args:
      employee_id: "str"
      include_ssn: "bool"
    policy:
      - args.include_ssn & !perm.view_ssn: deny
    result:
      salary: "int | taint(PII, session) | redact(!role.hr)"
      ssn: "str | taint(PII, session) | redact(!perm.view_ssn)"
      employee_id: "str | mask(4)"
      internal_notes: "omit"

Composes hard and soft policy engines

APL conditions can dispatch to OPA, Cedar, AuthZEN, or NeMo Guardrails — with configurable side effects per decision. The same attribute context feeds every engine:

routes:
  - tool: get_compensation
    meta:
      tags: [pii]
    args:
      employee_id: "str"
      include_ssn: "bool"
    policy:
      # APL built-in — fast attribute checks (<1ms, Rust)
      - args.include_ssn & !perm.view_ssn: deny

      # OPA — complex authorization logic in Rego
      - opa:
          endpoint: "http://opa-sidecar:8181"
          package: "hr.compensation"
          input_namespaces: [subject, delegation, session]

    result:
      salary: "int | taint(PII, session) | redact(!role.hr)"
      ssn: "str | taint(PII, session) | redact(!perm.view_ssn)"
      employee_id: "str | mask(4)"

  - tool: send_email
    policy:
      # APL — session taint blocks data exfiltration
      - session.labels contains "PII": deny

      # NeMo — scan email body for leaked PII
      - nemo(args.body):
          config_id: "pii-detection"
          on_match: deny

APL is not a replacement for OPA, Cedar, or NeMo. It's the orchestration layer that brings them together — one route, multiple engines, one pipeline. Each engine evaluates against the same CMF-normalized attribute context. APL handles what happens with the decision (deny, taint, transform).

Decides AND modifies

APL goes beyond allow/deny. Policy rules can transform the data flowing through the pipeline — field-level redaction, masking, omission, and session taint tracking:

result:
  salary: "int | taint(PII, session) | redact(!role.hr)"
  ssn: "str | taint(PII, session) | redact(!perm.view_ssn)"
  employee_id: "str | mask(4)"
  internal_notes: "omit"

Each pipe chain reads left to right: validate the type, taint the session, then conditionally redact based on caller attributes. The same tool returns different data to different callers — zero changes to the tool itself.

Session-aware security

Labels accumulate monotonically across tool calls within a session. Once an agent touches sensitive data, the session is tainted and downstream actions are restricted:

1. Agent calls get_compensation → salary accessed → session tainted with [PII]
2. Agent calls send_email → session.labels contains "PII" → DENIED
3. Agent calls display_compensation → view action → ALLOWED (no forwarding)

Session taint is the mechanism that prevents data exfiltration through normal agent workflows. Traditional per-request authorization can't do this — it evaluates each call in isolation.

Pre-invoke and post-invoke policy

Policy evaluation happens in two phases, separated by the actual tool call:

Pre-invoke — Can the caller make this request?

policy:
  - args.include_ssn & !perm.view_ssn: deny
  - delegation.depth > 2: deny

Post-invoke — Given what the tool returned, should the response be allowed?

post_policy:
  - exists(result.ssn) & !perm.view_ssn: deny
  - session.labels contains "PII" & !perm.pii_access: deny

Post-invoke policy enables decisions based on actual results — not just what was requested.

Attribute-based evaluation

Every decision is made by evaluating attributes from across the system:

Namespace Source Examples
Subject Identity token (JWT, mTLS) role.hr, perm.view_ssn, subject.teams
Delegation Token exchange chain delegation.depth, delegation.origin, delegated
Session Accumulated state session.labels, session.tool_calls, session.cost
Meta Host-provided metadata meta.tags, meta.scope, meta.properties.owner
Content Tool args / results args.employee_id, result.salary

All attributes are collected into an AttributeBag — a flat namespace that any predicate can reference. The same bag feeds APL's built-in evaluator, OPA, Cedar, NeMo, and AuthZEN.

What This Enables

Capability What it does
Identity Resolution Separates agent credentials from user identity. User's JWT → roles, permissions, teams in the attribute bag.
Result Transforms Field-level redaction, masking, omission on tool results — driven by attributes, not hardcoded logic.
Session Taint Tracking Labels accumulate across tool calls. PII access taints the session; forwarding is blocked.
Token Delegation RFC 8693 token exchange mints narrowed, audience-scoped credentials for downstream tools.
Policy Composition OPA, Cedar, NeMo, AuthZEN in the same pipeline over the same attribute context.

Built On

  • CMF (Contextual Message Format) — Protocol-agnostic message format that normalizes tool calls, identity, delegation, session, and security labels into a single envelope. CMF is what makes APL portable across MCP, A2A, REST, and gRPC.

  • CPEX (ContextForge Plugin Extensibility Framework) — Hook-based plugin runtime that embeds enforcement points at every stage of the agentic lifecycle. CPEX is where APL plugs in — alongside OPA, NeMo, and custom plugins.

30-Second Demo

An engineer and an HR manager both ask an AI agent to look up the same employee's compensation:

Engineer (Alice):                    HR Manager (Bob):
  salary: [REDACTED]                   salary: 125000
  employee_id: ******1234              employee_id: ******1234
  internal_notes: (omitted)            internal_notes: (omitted)
  SSN request: DENIED                  SSN: 123-45-6789

Bob then tries to email the data externally:
  send_email: DENIED (session tainted with PII)

Alice views a compensation summary:
  display_compensation: ALLOWED

Same agent, same gateway, same tool. Different results based on identity, permissions, and session history. Zero changes to the HR tool.

Specification

The full APL DSL specification is available at APL Specification. It covers:

  • Policy structure (global policies, defaults, routes, evaluation order)
  • Predicate language (require, exists, comparisons, set operators, logical combinators)
  • Effects (deny, allow, taint, plugin, sequential/parallel orchestration)
  • Pipe chains (field-level validation and transforms)
  • External PDP integration (OPA, Cedar, AuthZEN, NeMo with reaction model)
  • Complete EBNF grammar

The specification documents implemented behavior. The APL core is built in Rust with Python (PyO3) bindings, providing sub-millisecond evaluation per request.

Another document is the unified configuration doc which describes how APL fits with the broader CPEX configuration.

Get Involved

We're looking for feedback on:

  • The policy language design — Does the predicate-and-effects model cover your agentic security use cases?
  • External PDP integration — Is the OPA/Cedar/AuthZEN/NeMo integration model sufficient for your environment?
  • Session taint semantics — Are monotonic session labels the right primitive for data flow control?
  • Attribute namespaces — Are there attributes missing from the AttributeBag that your policies need?
  • Post-invoke policy — What post-invoke decisions do you need beyond what post_policy provides?

Comments, questions, and contributions welcome.

Metadata

Metadata

Assignees

Labels

No fields configured for Feature.

Projects

Status
Backlog

Relationships

None yet

Development

No branches or pull requests

Issue actions