Skip to content

ACK-ID: signed A2A messages carry no aud claim and verifyA2ASignedMessage ignores its did option #224

Description

@byfor8

Summary

createSignedA2AMessage signs only { jti, message } with no aud claim (the A2A message schema has no recipient field), and verifyA2ASignedMessage destructures away its did option and calls verifyJwt with only issuer and resolver. Nothing in verification binds the intended recipient. The repo's own tests document this ("Signed messages carry no aud claim today").

Contrast in the same repo

The handshake path does it correctly: createA2AHandshakePayload sets aud: params.recipient and verifyA2AHandshakeMessage passes audience: did to verifyJwt.

Reproduction (source level)

  1. Agent A signs a message for agent B via createSignedA2AMessage.
  2. Agent C obtains the signed message (shared bus, log, relay) and presents it to any service that trusts A.
  3. The service calls verifyA2ASignedMessage(msg, { did: <its own did>, counterparty: A }); the did option is ignored, verification succeeds, and C is treated as the intended recipient for the message's 5 minute lifetime.

verifyJwt's missing-audience guard (jwt package verify.ts) only fires when an audience option is supplied, which never happens on this path. Counterparty is bound only if the caller separately passes issuer.

Impact

A message intended for one agent is accepted by any agent or service that trusts the issuer. Recipient-bound authorization decisions built on signed A2A messages rest on an unbound token.

Suggested fix

Include aud in the signed payload (new optional recipient field on the message schema, or a verify-time option) and pass audience to verifyJwt in verifyA2ASignedMessage, mirroring the handshake path. Alternatively document loudly that callers MUST pass issuer and treat verification as sender-authentication only.

Environment: agentcommercekit/ack at commit b5b25ce (main as of 2026-09-12). Reviewed at source level; no live systems were tested.

Disclosure note: reported to security@agentcommercekit.com per SECURITY.md on 2026-09-14; a maintainer asked for these to be filed publicly, so they are here.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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