You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
AdCP 3.3: A2A operation-resolution hardening is MUST; advertise request_signing.operation_sources #1637
The A2A operation-resolution errata (GHSA-2pm6-6mc8-8xcm) shipped in 3.2.3 with its hardening clauses at SHOULD. From 3.3 they're MUST for every verifier, whether or not it advertises the marker. See the migration guide §A2A operation-resolution hardening becomes MUST and security.mdx §Operation resolution over A2A (tag v3.3.0-beta.0):
Strict parsing of unsigned bodies, including JSON-RPC batches and duplicate or case-variant member names. Duplicate keys are detected after JSON string decoding ("skill" and "skill" collide).
A2A Part shape: one content member per Part, no FilePart, and kind agreement.
Task-continuation binding: a message.taskId request must resolve to the task's original operation and come from the principal that created it.
The new optional capability request_signing.operation_sources (mcp_tools_call, a2a_invocation_skill) declares support. A present array must list every source the verifier supports.
Current state
server/signed_requests.py::_jsonrpc_target parses with json.loads, which silently keeps the last duplicate. parse_a2a_jsonrpc_skill validates through a2a-sdk models. Part-shape and continuation binding still need auditing.
Work
Strict duplicate- and case-variant-key detection (reuse signing/_strict_json.py if it fits) on the operation-resolution path; fail closed with request_body_malformed.
Part-shape checks; reject more than one DataPart on an invocation.
Bind taskId continuations to the original operation and principal.
Run the A2A conformance vectors, including the hardening tier, if the 3.3 bundle ships them.
After regen: advertise request_signing.operation_sources from RequestSignatureVerification when enabled.
Batch: A (enforcement; hand-written). The capability advertisement follows in batch D.
PR #1659 enforces the three MUST clauses when request signing is configured. All 33 A2A operation-resolution vectors from v3.3.0-beta.0 pass, including the hardening tier.
Follow-ups, still open here:
adcp_task_binding (the operation and an unsalted SHA-256 of tenant and principal) rides in client-visible Task.metadata. Strip it from client-facing task payloads, or move it to server-side storage.
Unsigned servers: the executor's default parser still accepts the TextPart JSON fallback and extra DataParts.
input member: the default parser reads parameters but not the A2A profile's input member.
Discovery bypass:server/auth.py's discovery-skill bypass parses without the strict resolver.
Activity
fix(a2a): answer a continuation principal mismatch as task-not-found
bokelley commentedon Oct 27, 2026
PR #1659 enforces the three MUST clauses when request signing is configured. All 33 A2A operation-resolution vectors from v3.3.0-beta.0 pass, including the
hardeningtier.Follow-ups, still open here:
adcp_task_binding(the operation and an unsalted SHA-256 of tenant and principal) rides in client-visibleTask.metadata. Strip it from client-facing task payloads, or move it to server-side storage.inputmember: the default parser readsparametersbut not the A2A profile'sinputmember.server/auth.py's discovery-skill bypass parses without the strict resolver._json_bounds, AdCP 3.3: bound inbound push/webhook bodies before signature verification, and response JSON depth/node count #1636) inSignedRequestVerificationMiddleware.__call__after the body is buffered, and in_jsonrpc_target/_a2a_targetbeforeparse_strict_json.request_signing.operation_sources.fix(a2a)!: enforce the AdCP 3.3 operation-resolution hardening clauses
fix(a2a): answer a continuation principal mismatch as task-not-found
fix(a2a)!: enforce the AdCP 3.3 operation-resolution hardening clauses (