docs(order): webhook example must sign ucp-agent (identity otherwise unbound) - #568
Closed
vishkaty wants to merge 2 commits into
Closed
Conversation
vishkaty
added a commit
to vishkaty/ucp
that referenced
this pull request
Jul 16, 2026
…alues Extends the sweep per review: the response-signing examples used a second DER shape (MFQCIH..., a 0x30-led SEQUENCE) that the first pass's pattern missed — now swept by decoding every example signature value's leading byte rather than pattern-matching. Fixes checkout-mcp.md, checkout-rest.md, and signatures.md's response-signing example, and aligns the stale keyid="merchant-2025" with the merchant-2026 used by every sibling example. order.md's instance remains deferred to avoid overlapping Universal-Commerce-Protocol#568.
damaz91
requested review from
DanielFalconGuedes and
jingyli
and removed request for
a team
July 20, 2026 13:28
damaz91
pushed a commit
that referenced
this pull request
Jul 24, 2026
…requires (#590) * docs(signatures): make example signature values raw r||s as the spec requires signatures.md mandates fixed-width raw r||s encoding for ECDSA signature values ("MUST use fixed-width raw r||s encoding"), but the worked examples showed values beginning ME[UQ]C... — the base64 of a DER SEQUENCE, the exact encoding the normative text forbids. An implementer copying the examples' shape produces signatures a conformant verifier rejects. Replaces the seven example values in signatures.md, checkout-mcp.md, checkout-rest.md, and order-rest.md with a genuine ES256 raw r||s value (64 bytes, 88 base64 chars), preserving each instance's truncation style. The instance in order.md is deliberately left to avoid overlapping #568, which edits the same example block. Fixes #569. * docs(signatures): fix remaining DER-shaped response-signing example values Extends the sweep per review: the response-signing examples used a second DER shape (MFQCIH..., a 0x30-led SEQUENCE) that the first pass's pattern missed — now swept by decoding every example signature value's leading byte rather than pattern-matching. Fixes checkout-mcp.md, checkout-rest.md, and signatures.md's response-signing example, and aligns the stale keyid="merchant-2025" with the merchant-2026 used by every sibling example. order.md's instance remains deferred to avoid overlapping #568.
The example webhook request carries a UCP-Agent header but its Signature-Input omits the ucp-agent component. signatures.md's request signed-component table requires ucp-agent whenever the UCP-Agent header is present, and webhook identity is derived from that header — so the example as written leaves the sender identity cryptographically unbound and contradicts the table it illustrates.
Same class as the order.md webhook example fix: the example carries the UCP-Agent header but omits ucp-agent from the covered components, leaving the signer identity unbound. checkout-rest.md itself requires the header on all requests, so per the signatures.md component table it must be signed. Matches the component order of the canonical request example in signatures.md.
vishkaty
force-pushed
the
fix/webhook-example-sign-ucp-agent
branch
from
July 24, 2026 13:37
0ece9a2 to
4b35d52
Compare
vishkaty
pushed a commit
to vishkaty/ucp
that referenced
this pull request
Jul 31, 2026
… webhook signature The order event webhook lists Webhook-Id and Webhook-Timestamp as required headers and states that headers follow Standard Webhooks, but the signing and verification steps never cover them, and the example Signature-Input signs only method, authority, path, content-digest, and content-type. Webhooks carry no Idempotency-Key, so these headers are the only per-delivery replay signal; as written a captured, validly signed delivery can be replayed with an altered Webhook-Id or Webhook-Timestamp. The overview verification gate already anticipates this: a header outside the default covered set is gate-required when its defining section says so. Have the order webhook section say so for webhook-id and webhook-timestamp, require platforms to verify their coverage, and require deduplication on Webhook-Id. Update the signing and verification steps and the example accordingly. The example also now covers ucp-agent, which the overview gate already requires whenever the UCP-Agent header is present (it was missing from this example); this binds the signer identity on the webhook and subsumes the webhook-example change in Universal-Commerce-Protocol#568. Also drop the stale event_id and created_time from the example body and the playground payload builder (moved to headers in Universal-Commerce-Protocol#342), and show the required Webhook-Id and Webhook-Timestamp headers in the example.
Contributor
Author
|
Superseding this with #659. This PR's purpose is signing This PR also added |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The "Example Webhook Request" in
docs/specification/order.mdcarries aUCP-Agentheader but itsSignature-Inputsigns only("@method" "@authority" "@path" "content-digest" "content-type")— omittingucp-agent.This contradicts the normative signed-component rules in
signatures.md:ucp-agent"Required ifUCP-Agentheader is present" (the**footnote), and there is no separate webhook component table.signatures.mdexplicitly derives webhook identity from theUCP-Agentheader ("Business → Platform webhooks: Profile URL fromUCP-Agentheader") and requires webhooks to be signed.Because the example doesn't sign
ucp-agent, the sender's identity (the component's documented purpose — "binds identity") is not cryptographically bound in the illustrated signature, and a platform copying the example produces a signature that a table-following verifier would reject.One-line fix: add
ucp-agentto the example's signed components, matching the request example insignatures.md.Found while building an unofficial UCP conformance test suite (https://spck.dev); verified against main @ 7e5fc42.
Update (class sweep): re-checked every RFC 9421 example in
docs/for this same pattern (UCP-Agent header present but not among the signed components). One more instance:checkout-rest.md's "Example Signed Request" — fixed in the second commit with the same one-line change, matching the component order of the canonical request example insignatures.md. All other examples either already signucp-agent, omit the header entirely, or are response/elided examples where the component doesn't apply.