Skip to main content

AOC-3: Requester Identity Propagation

Shipped: March 2026 (all three phases complete)


The problem

When an agent acts, it does so on behalf of a human user. But until AOC-3, Behavry only knew which agent made a tool call — not who told it to. A compromised agent could masquerade as any user, and the audit trail would show only the agent. In multi-agent workflows, the problem compounds: Agent B delegates to Agent C, and the original requester's identity is lost entirely.


How it works

Phase 1 — Header propagation

The Behavry SDK injects an X-Requester-Id header on every tool call:

# Set via environment variable
BEHAVRY_REQUESTER_ID=user@company.com

The proxy extracts this and stores it alongside every audit event:

{
"requester_id": "user@company.com",
"requester_channel": "claude-code",
"requester_verified": false
}

Phase 2 — Mismatch detection

The Behavioral Monitor watches for requester identity mismatches — cases where a single agent is acting on behalf of multiple distinct requesters within a 15-minute window. This pattern indicates either a compromised agent or session hijacking.

A REQUESTER_IDENTITY_MISMATCH alert fires and the session is flagged for review.

Phase 3 — Delegation token chain (Sprint U)

Phase 3 adds cryptographic proof of requester identity through delegation tokens (d_tokens). When an agent within a workflow session delegates a subset of its permissions to another agent, a signed JWT encodes exactly what the delegatee is allowed to do — and who authorized it.

Issuing a delegation

POST /api/v1/delegations
Content-Type: application/json

{
"workflow_session_id": "ws_abc123",
"delegator_agent_id": "agent-orchestrator",
"delegatee_agent_id": "agent-researcher",
"scope": {
"tools": ["search_web", "read_file"],
"resources": ["/data/public/*"],
"max_data_volume_mb": 10
},
"reason": "Research subtask for quarterly report",
"ttl_seconds": 1800
}

The delegation service enforces three invariants before minting the token:

  1. Scope intersection — the delegatee's effective permissions are the intersection of the requested scope and the delegator's own ceiling (from the workflow session token or a parent delegation). You cannot grant more than you have.
  2. Ceiling guard — if any requested tool or resource falls outside the delegator's ceiling, the request is rejected with SCOPE_EXCEEDS_DELEGATOR.
  3. Depth guard — each delegation increments a depth counter. If delegation_depth exceeds the session's max_depth, the request is rejected with DEPTH_EXCEEDS_MAX.

The response includes a d_token JWT and a DelegationRead object with the computed effective_permissions.

Using a delegation token

The delegatee passes the token on every proxy request:

X-Delegation-Token: eyJhbGciOiJSUzI1NiIs...
X-Workflow-Session: <wf_token>

The proxy engine validates the token at step 2e of the enforcement pipeline:

  1. Decode the RS256 JWT (same key ring as agent and workflow tokens)
  2. Confirm the delegatee_id matches the calling agent
  3. Confirm the workflow_session_id matches the X-Workflow-Session header
  4. Verify the corresponding Delegation database row is active and not expired

On success, the engine sets requester_verified = True — the cryptographic proof that AOC-3 Phase 1 lacked.

Scope probe detection

When a delegatee makes a tool call that falls outside its effective_permissions.tools, the engine tracks this as a scope probe. After 3 scope probes within the same (agent_id, session_id) window, a DELEGATION_SCOPE_PROBE alert fires. This pattern often indicates a prompt injection attempting to enumerate available permissions.

The scope probe counter resets after the alert fires, so persistent probing generates repeated alerts.

Revoking a delegation

POST /api/v1/delegations/{delegation_id}/revoke

Revocation is immediate. Any subsequent proxy request carrying the revoked d_token is rejected — the enforcer checks the database row status on every call, not just the JWT expiry.

Chained delegations

Delegations can be chained: Agent A delegates to Agent B, and Agent B further delegates to Agent C. Each link in the chain narrows scope (never widens it) and increments the depth counter. The parent_delegation_id field in the JWT and database row maintains the full provenance chain.

Orchestrator (ceiling: full workflow permissions)
└─ d_token_1 → Researcher (scope: search_web, read_file)
└─ d_token_2 → Summarizer (scope: read_file only)

OPA policy enforcement

The delegation policy at package behavry.delegation.policy evaluates three conditions:

ConditionResultDescription
Delegation verified, tool in scopeallowNormal authorized operation
Delegation verified, tool not in scopeescalateScope probe — HITL review
Delegation not verifieddenyToken validation failed

The requester identity policy (package behavry.requester) was also updated: requests with critical severity and an unverified requester are blocked; high severity with an unverified requester triggers escalation.


Instruction hash

Every inbound tool call body is SHA-256 hashed and stored as instruction_hash. This allows:

  • Auditing whether the same instruction was reused across sessions
  • Detecting copy-paste injection attacks
  • Proving that an instruction was not tampered with

Dashboard

The Audit Events tab shows a Requester column with the identity and verification status of every action. Delegated actions show a verification badge when backed by a valid d_token.

Agentic Security Overview