Summary
When OpenAgents HttpTransport serves A2A, it creates a shared in-memory task store and converts A2A contextId into downstream Event.thread_name = a2a:{contextId}. In the replay, Bob reads and lists Alice's task by task id, continues Alice's task, and reuses Alice's context to inherit downstream thread state.
Affected Target Verified
- Repository:
https://github.com/openagents-org/openagents
- Component: HTTP transport with
serve_a2a enabled
- Affected commit verified:
1c19c607454edc08b8357a204c4dbd3648975b81
- Vulnerability type: Cross-caller task/history disclosure and context rebinding
Preconditions
serve_a2a: true is enabled on a shared HTTP transport.
- Multiple callers can reach the same A2A surface.
- No outer middleware binds A2A task/context ids to caller identity.
Steps To Reproduce
From the attachment directory:
The script clones the target repository, checks out the verified commit, prepares a local test environment, and runs the bundled PoC. It does not contact attacker-controlled services; the setup only downloads the public repository and normal build dependencies.
To run against an existing checkout:
OPENAGENTS_TARGET_DIR=/path/to/checkout bash reproduce.sh
The wrapper accepts OPENAGENTS_TARGET_DIR for an existing checkout. It also accepts the target commit override documented in attachments/reproduce.sh.
Technical Details
InMemoryTaskStore is keyed by bare task id and context id. The A2A converter derives downstream thread name directly from caller-controlled contextId.
Expected Behavior
When serve_a2a is used on a shared HTTP transport, task lookup/listing,
task continuation, and context-to-thread conversion should be partitioned by a
trusted caller or tenant boundary. A bare task id or contextId should not
resume another caller's downstream thread.
Actual Behavior
- Bob
tasks/get receives Alice task and secret-bearing artifact/history.
- Bob
tasks/list returns Alice task when no context filter is supplied.
- Bob
message/send(taskId=<alice>) appends to Alice task.
- Bob same-context request receives Alice prior thread history; fresh-context control does not.
Impact
Task ids and context ids act as reusable cross-caller handles for task history
and downstream conversation state on shared HTTP transports. In the reproduced
flow, Bob reads Alice's task, sees Alice's secret-bearing artifact/history,
appends to Alice's task by sending message/send(taskId=<alice>), and reuses
Alice's contextId to inherit downstream thread history.
For OpenAgents deployments using serve_a2a as a shared transport, this can
expose prompts, responses, artifacts, and thread-local state from another
caller. It can also let one caller contaminate another caller's task by
appending messages or continuing under the same downstream thread name.
The fresh-context control shows the leak is not simply a global model memory
effect. The collision follows the A2A task/context selectors that are stored or
converted without a trusted caller partition.
Suggested Fix
Partition the A2A task store and context-to-thread conversion by authenticated caller or tenant. Do not list or resume tasks outside the caller's authority boundary.
Attachments
attachments.zip
Summary
When OpenAgents
HttpTransportserves A2A, it creates a shared in-memory task store and converts A2AcontextIdinto downstreamEvent.thread_name = a2a:{contextId}. In the replay, Bob reads and lists Alice's task by task id, continues Alice's task, and reuses Alice's context to inherit downstream thread state.Affected Target Verified
https://github.com/openagents-org/openagentsserve_a2aenabled1c19c607454edc08b8357a204c4dbd3648975b81Preconditions
serve_a2a: trueis enabled on a shared HTTP transport.Steps To Reproduce
From the attachment directory:
The script clones the target repository, checks out the verified commit, prepares a local test environment, and runs the bundled PoC. It does not contact attacker-controlled services; the setup only downloads the public repository and normal build dependencies.
To run against an existing checkout:
The wrapper accepts
OPENAGENTS_TARGET_DIRfor an existing checkout. It also accepts the target commit override documented inattachments/reproduce.sh.Technical Details
InMemoryTaskStoreis keyed by bare task id and context id. The A2A converter derives downstream thread name directly from caller-controlledcontextId.Expected Behavior
When
serve_a2ais used on a shared HTTP transport, task lookup/listing,task continuation, and context-to-thread conversion should be partitioned by a
trusted caller or tenant boundary. A bare task id or
contextIdshould notresume another caller's downstream thread.
Actual Behavior
tasks/getreceives Alice task and secret-bearing artifact/history.tasks/listreturns Alice task when no context filter is supplied.message/send(taskId=<alice>)appends to Alice task.Impact
Task ids and context ids act as reusable cross-caller handles for task history
and downstream conversation state on shared HTTP transports. In the reproduced
flow, Bob reads Alice's task, sees Alice's secret-bearing artifact/history,
appends to Alice's task by sending
message/send(taskId=<alice>), and reusesAlice's
contextIdto inherit downstream thread history.For OpenAgents deployments using
serve_a2aas a shared transport, this canexpose prompts, responses, artifacts, and thread-local state from another
caller. It can also let one caller contaminate another caller's task by
appending messages or continuing under the same downstream thread name.
The fresh-context control shows the leak is not simply a global model memory
effect. The collision follows the A2A task/context selectors that are stored or
converted without a trusted caller partition.
Suggested Fix
Partition the A2A task store and context-to-thread conversion by authenticated caller or tenant. Do not list or resume tasks outside the caller's authority boundary.
Attachments
attachments.zip