Skip to content
ATR-2026-00548highContext Exfiltrationdraft

Cross-agent session context leak across delegation chain

Detects cross-agent context leakage in multi-agent systems where a privileged context attribute (typically session.id, user.id, or conversation.id) fails to remain constant across a single agent delegation chain. This is a trace-method rule that operates on agent execution traces in OpenInference format, not on input text. Threat model: in a multi-agent workflow, Agent A delegates to Agent B; B may legitimately spawn sub-agents to complete the task. The invariant ATR enforces is that the SAME session/user/conversation identifier MUST hold across every span in one delegation chain. If a downstream agent retrieves context from a DIFFERENT session (e.g., a tenant other than the original caller's) and folds it into its reasoning, the trace exhibits an attribute drift on the affected key. This pattern matches the cross-task / cross- tenant context leak class formalized in Argus (arXiv 2512.08326) and the compositional privacy risk taxonomy (arXiv 2509.14284). Detection covers (a) session.id drift across spans in agent.delegation_chain, (b) user.id drift across the same chain. The rule uses the `invariant` trace primitive defined in spec/atr-method-v1.1.md §8.3.3.

Severity
high
Category
Context Exfiltration
Scan Target
runtime
Author
ATR Community

Response Actions

alertquarantine session

References

OWASP Agentic
ASI03:2026 - Data ExfiltrationASI06:2026 - Identity Spoofing & Impersonation
MITRE ATLAS
AML.T0024 - Exfiltration via Cyber Means

Detection Conditions

Combinator: any
  1. 01
    Engine emits this synthetic field when the trace invariant fires; present for pattern-method engines that consume trace verdicts as text. Trace-native engines evaluate detection.trace below directly.
    field: trace.invariant_session_idop: regex

Attack Examples (Rule Triggers)

  1. {"spans":[{"id":"s1","kind":"AGENT","attributes":{"session.id":"sess_A","user.id":"u_001","agent.delegation_chain":"chain_1"}},{"id":"s2","kind":"AGENT","attributes":{"session.id":"sess_B","user.id":"u_001","agent.delegation_chain":"chain_1"}}]}
    
  2. {"spans":[{"id":"s1","kind":"AGENT","attributes":{"session.id":"sess_X","user.id":"u_100","agent.delegation_chain":"chain_2"}},{"id":"s2","kind":"RETRIEVER","attributes":{"session.id":"sess_X","user.id":"u_999","agent.delegation_chain":"chain_2"}}]}
    
  3. {"spans":[{"id":"s1","kind":"AGENT","attributes":{"session.id":"a","user.id":"alice","agent.delegation_chain":"c1"}},{"id":"s2","kind":"TOOL","attributes":{"session.id":"a","user.id":"alice","agent.delegation_chain":"c1"}},{"id":"s3","kind":"AGENT","attributes":{"session.id":"b","user.id":"alice","agent.delegation_chain":"c1"}}]}
    
  4. {"spans":[{"id":"r1","kind":"AGENT","attributes":{"session.id":"tenant_A_sess","user.id":"a","agent.delegation_chain":"d1"}},{"id":"r2","kind":"AGENT","attributes":{"session.id":"tenant_B_sess","user.id":"b","agent.delegation_chain":"d1"}}]}
    
  5. {"spans":[{"id":"x1","kind":"AGENT","attributes":{"session.id":"sess_1","user.id":"u","agent.delegation_chain":"e1"}},{"id":"x2","kind":"TOOL","attributes":{"tool.name":"db.query","session.id":"sess_2","user.id":"u","agent.delegation_chain":"e1"}}]}
    

Real-world attack payloads (sanitized). Used for regression testing.

Benign Examples (Rule Doesn't Trigger)

  1. Constant session.id and user.id across the chain — no drift
    {"spans":[{"id":"s1","kind":"AGENT","attributes":{"session.id":"sess_A","user.id":"u_001","agent.delegation_chain":"chain_1"}},{"id":"s2","kind":"AGENT","attributes":{"session.id":"sess_A","user.id":"u_001","agent.delegation_chain":"chain_1"}}]}
    
  2. Different delegation chains — invariant scoped per chain, so different sessions across chains is permitted
    {"spans":[{"id":"s1","kind":"AGENT","attributes":{"session.id":"sess_X","user.id":"u_100","agent.delegation_chain":"chain_2"}},{"id":"s2","kind":"AGENT","attributes":{"session.id":"sess_Y","user.id":"u_100","agent.delegation_chain":"chain_DIFFERENT"}}]}
    
  3. Single-span chain — no invariant to violate
    {"spans":[{"id":"alone","kind":"AGENT","attributes":{"session.id":"sess_solo","user.id":"u","agent.delegation_chain":"c"}}]}
    
  4. Three spans, all consistent — invariant holds
    {"spans":[{"id":"s1","kind":"AGENT","attributes":{"session.id":"abc","user.id":"alice","agent.delegation_chain":"k1"}},{"id":"s2","kind":"TOOL","attributes":{"tool.name":"calculator","session.id":"abc","user.id":"alice","agent.delegation_chain":"k1"}},{"id":"s3","kind":"AGENT","attributes":{"session.id":"abc","user.id":"alice","agent.delegation_chain":"k1"}}]}
    
  5. Public retrieval chain without user.id (anonymous query) — no per-user drift to flag
    {"spans":[{"id":"p1","kind":"RETRIEVER","attributes":{"session.id":"public_search","agent.delegation_chain":"public_chain"}},{"id":"p2","kind":"LLM","attributes":{"session.id":"public_search","agent.delegation_chain":"public_chain"}}]}
    

Known False Positive Contexts

  • Delegation chain naming convention dependency: the rule assumes attributes.agent.delegation_chain holds a per-invocation unique ID (e.g., UUID per delegation). If a framework serializes it as a static role name ("main_chain", "default") shared across unrelated invocations, spans from different requests will appear in the same chain and the invariant will fire spuriously. Mitigation: operators MUST verify their framework emits chain IDs that are unique per invocation; for frameworks that emit static names, use attributes.gen_ai.conversation.id as the across-domain instead (requires rule variant; see roadmap).
  • Anonymous public retrieval chains: when a chain processes requests without user.id (anonymous public API), the rule's user.id invariant is vacuously satisfied (no value to compare). This is correct behavior, documented in TN #5.

Full YAML Definition

Edit on GitHub →
title: "Cross-agent session context leak across delegation chain"
id: ATR-2026-00548
rule_version: 1
status: draft
description: >
  Detects cross-agent context leakage in multi-agent systems where a privileged
  context attribute (typically session.id, user.id, or conversation.id) fails
  to remain constant across a single agent delegation chain. This is a
  trace-method rule that operates on agent execution traces in OpenInference
  format, not on input text.

  Threat model: in a multi-agent workflow, Agent A delegates to Agent B; B may
  legitimately spawn sub-agents to complete the task. The invariant ATR
  enforces is that the SAME session/user/conversation identifier MUST hold
  across every span in one delegation chain. If a downstream agent retrieves
  context from a DIFFERENT session (e.g., a tenant other than the original
  caller's) and folds it into its reasoning, the trace exhibits an attribute
  drift on the affected key. This pattern matches the cross-task / cross-
  tenant context leak class formalized in Argus (arXiv 2512.08326) and the
  compositional privacy risk taxonomy (arXiv 2509.14284).

  Detection covers (a) session.id drift across spans in
  agent.delegation_chain, (b) user.id drift across the same chain. The rule
  uses the `invariant` trace primitive defined in
  spec/atr-method-v1.1.md §8.3.3.
author: "ATR Community"
date: "2026/05/28"
schema_version: "1.0"
maturity: draft
severity: high

references:
  owasp_agentic:
    - "ASI03:2026 - Data Exfiltration"
    - "ASI06:2026 - Identity Spoofing & Impersonation"
  mitre_atlas:
    - "AML.T0024 - Exfiltration via Cyber Means"
  research:
    - "Argus: Hierarchical Reference-Relationship Graph for Multi-Agent Information Leakage (arXiv:2512.08326)"
    - "Compositional Privacy Risks in Multi-Agent Systems (arXiv:2509.14284)"

compliance:
  nist_csf:
    - "DE.CM-09"
  etsi_ts_104223:
    - "P4.3"
  eu_ai_act:
    - article: "10"
      context: >
        Data governance — multi-agent systems must preserve session-scope
        boundaries; cross-tenant leakage via delegation is a data-governance
        failure under Article 10.
      strength: primary
  nist_ai_rmf:
    - subcategory: "MS.2.6"
      context: >
        Information security — agent delegation chains must preserve session
        and user scope; attribute drift across spans is an integrity violation.
      strength: primary

tags:
  category: context-exfiltration
  subcategory: cross-agent-context-drift
  scan_target: runtime
  confidence: high
  source: trace-rule

agent_source:
  type: agent_trace
  framework:
    - any
  provider:
    - any

detection:
  method: trace
  condition: any
  false_positives:
    - >
      Delegation chain naming convention dependency: the rule assumes
      attributes.agent.delegation_chain holds a per-invocation unique ID
      (e.g., UUID per delegation). If a framework serializes it as a
      static role name ("main_chain", "default") shared across unrelated
      invocations, spans from different requests will appear in the same
      chain and the invariant will fire spuriously. Mitigation: operators
      MUST verify their framework emits chain IDs that are unique per
      invocation; for frameworks that emit static names, use
      attributes.gen_ai.conversation.id as the across-domain instead
      (requires rule variant; see roadmap).
    - >
      Anonymous public retrieval chains: when a chain processes requests
      without user.id (anonymous public API), the rule's user.id
      invariant is vacuously satisfied (no value to compare). This is
      correct behavior, documented in TN #5.
  conditions:
    - field: trace.invariant_session_id
      operator: regex
      value: "(?i)invariant_violation:session.id_changed"
      description: >
        Engine emits this synthetic field when the trace invariant fires;
        present for pattern-method engines that consume trace verdicts as
        text. Trace-native engines evaluate detection.trace below directly.
  trace:
    ingest_format: openinference
    invariant:
      - attribute: "session.id"
        across: "agent.delegation_chain"
        description: >
          session.id MUST remain constant across every span in one
          delegation chain. Drift indicates downstream agent operated under
          a different session scope.
      - attribute: "user.id"
        across: "agent.delegation_chain"
        description: >
          user.id MUST remain constant across the delegation chain. Drift
          indicates the downstream agent processed a different user's data.

response:
  actions:
    - alert
    - quarantine_session
  message_template: >
    [ATR-2026-00548] HIGH: Cross-agent session context leak detected. The
    delegation chain starting at span {{trace.root_span_id}} exhibits drift
    on attribute {{trace.violated_invariant}}; span {{trace.first_drifted_span_id}}
    operated under a different session/user scope than the root. Quarantine
    the trace, preserve full span DAG for forensics, and audit data
    accessed by the drifted spans.

confidence: 85

wild_fp_rate: 0

test_cases:
  true_positives:
    - input: |
        {"spans":[{"id":"s1","kind":"AGENT","attributes":{"session.id":"sess_A","user.id":"u_001","agent.delegation_chain":"chain_1"}},{"id":"s2","kind":"AGENT","attributes":{"session.id":"sess_B","user.id":"u_001","agent.delegation_chain":"chain_1"}}]}
      expected: triggered
      description: "session.id drifts from sess_A to sess_B within one delegation chain"
    - input: |
        {"spans":[{"id":"s1","kind":"AGENT","attributes":{"session.id":"sess_X","user.id":"u_100","agent.delegation_chain":"chain_2"}},{"id":"s2","kind":"RETRIEVER","attributes":{"session.id":"sess_X","user.id":"u_999","agent.delegation_chain":"chain_2"}}]}
      expected: triggered
      description: "user.id drifts from u_100 to u_999 within one delegation chain"
    - input: |
        {"spans":[{"id":"s1","kind":"AGENT","attributes":{"session.id":"a","user.id":"alice","agent.delegation_chain":"c1"}},{"id":"s2","kind":"TOOL","attributes":{"session.id":"a","user.id":"alice","agent.delegation_chain":"c1"}},{"id":"s3","kind":"AGENT","attributes":{"session.id":"b","user.id":"alice","agent.delegation_chain":"c1"}}]}
      expected: triggered
      description: "session.id drifts on the third span of a three-span chain"
    - input: |
        {"spans":[{"id":"r1","kind":"AGENT","attributes":{"session.id":"tenant_A_sess","user.id":"a","agent.delegation_chain":"d1"}},{"id":"r2","kind":"AGENT","attributes":{"session.id":"tenant_B_sess","user.id":"b","agent.delegation_chain":"d1"}}]}
      expected: triggered
      description: "Cross-tenant chain: both session.id and user.id drift simultaneously"
    - input: |
        {"spans":[{"id":"x1","kind":"AGENT","attributes":{"session.id":"sess_1","user.id":"u","agent.delegation_chain":"e1"}},{"id":"x2","kind":"TOOL","attributes":{"tool.name":"db.query","session.id":"sess_2","user.id":"u","agent.delegation_chain":"e1"}}]}
      expected: triggered
      description: "TOOL span queries DB under different session than the parent AGENT span"

  true_negatives:
    - input: |
        {"spans":[{"id":"s1","kind":"AGENT","attributes":{"session.id":"sess_A","user.id":"u_001","agent.delegation_chain":"chain_1"}},{"id":"s2","kind":"AGENT","attributes":{"session.id":"sess_A","user.id":"u_001","agent.delegation_chain":"chain_1"}}]}
      expected: not_triggered
      description: "Constant session.id and user.id across the chain — no drift"
    - input: |
        {"spans":[{"id":"s1","kind":"AGENT","attributes":{"session.id":"sess_X","user.id":"u_100","agent.delegation_chain":"chain_2"}},{"id":"s2","kind":"AGENT","attributes":{"session.id":"sess_Y","user.id":"u_100","agent.delegation_chain":"chain_DIFFERENT"}}]}
      expected: not_triggered
      description: "Different delegation chains — invariant scoped per chain, so different sessions across chains is permitted"
    - input: |
        {"spans":[{"id":"alone","kind":"AGENT","attributes":{"session.id":"sess_solo","user.id":"u","agent.delegation_chain":"c"}}]}
      expected: not_triggered
      description: "Single-span chain — no invariant to violate"
    - input: |
        {"spans":[{"id":"s1","kind":"AGENT","attributes":{"session.id":"abc","user.id":"alice","agent.delegation_chain":"k1"}},{"id":"s2","kind":"TOOL","attributes":{"tool.name":"calculator","session.id":"abc","user.id":"alice","agent.delegation_chain":"k1"}},{"id":"s3","kind":"AGENT","attributes":{"session.id":"abc","user.id":"alice","agent.delegation_chain":"k1"}}]}
      expected: not_triggered
      description: "Three spans, all consistent — invariant holds"
    - input: |
        {"spans":[{"id":"p1","kind":"RETRIEVER","attributes":{"session.id":"public_search","agent.delegation_chain":"public_chain"}},{"id":"p2","kind":"LLM","attributes":{"session.id":"public_search","agent.delegation_chain":"public_chain"}}]}
      expected: not_triggered
      description: "Public retrieval chain without user.id (anonymous query) — no per-user drift to flag"

Revision History

Created
2026-05-28
Last modified
2026-05-28
View full commit history on GitHub →