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:
- 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.
- Ceiling guard — if any requested tool or resource falls outside the delegator's ceiling, the request is rejected with
SCOPE_EXCEEDS_DELEGATOR. - Depth guard — each delegation increments a depth counter. If
delegation_depthexceeds the session'smax_depth, the request is rejected withDEPTH_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:
- Decode the RS256 JWT (same key ring as agent and workflow tokens)
- Confirm the
delegatee_idmatches the calling agent - Confirm the
workflow_session_idmatches theX-Workflow-Sessionheader - Verify the corresponding
Delegationdatabase 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:
| Condition | Result | Description |
|---|---|---|
| Delegation verified, tool in scope | allow | Normal authorized operation |
| Delegation verified, tool not in scope | escalate | Scope probe — HITL review |
| Delegation not verified | deny | Token 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.