Skip to content

[BUG] OpenAgents HTTP A2A transport exposes shared task history and context-thread state #561

Description

@N0zoM1z0

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:

bash reproduce.sh

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions