-
Notifications
You must be signed in to change notification settings - Fork 65
Brand Protocol response-signing: payload-envelope JWS replay protection #4716
Copy link
Copy link
Open
Labels
brandIssue concerns the brand protocol domainIssue concerns the brand protocol domainclaude-triagedIssue has been triaged by the Claude Code triage routine. Remove to re-triage.Issue has been triaged by the Claude Code triage routine. Remove to re-triage.needs-wg-reviewBlocked on a working-group decision — surface in WG meeting agendasBlocked on a working-group decision — surface in WG meeting agendasseverity:significantspec / protocoltriage:verify-closeNeeds verification that linked work landed, then close if satisfiedNeeds verification that linked work landed, then close if satisfied
Milestone
Description
Metadata
Metadata
Assignees
Labels
brandIssue concerns the brand protocol domainIssue concerns the brand protocol domainclaude-triagedIssue has been triaged by the Claude Code triage routine. Remove to re-triage.Issue has been triaged by the Claude Code triage routine. Remove to re-triage.needs-wg-reviewBlocked on a working-group decision — surface in WG meeting agendasBlocked on a working-group decision — surface in WG meeting agendasseverity:significantspec / protocoltriage:verify-closeNeeds verification that linked work landed, then close if satisfiedNeeds verification that linked work landed, then close if satisfied
Type
Fields
Give feedbackNo fields configured for issues without a type.
Gap
The
verify_brand_claim/verify_brand_claimsresponse signature is a JWS payload envelope underadcp_use: "response-signing"(see security.mdx — designated-task response signing). The envelope schema currently carries no freshness binding — noiat, nononce, no echo of the request that triggered the response.Threat: an attacker (or stale cache) that captures one signed
disputedresponse can replay it indefinitely against any future query for the same claim. The trust model treats rejection direction as authoritative, which means a captured-and-replayeddisputedblocks legitimate future business association. The signature continues to verify under the brand's published key —disputedis permanent until the JWK rotates.Surfaced by the security-review pass on PR #4703 (#NNNN — link to be added). The reviewer flagged this as ship-blocking on the brand-protocol primitive itself, but out of scope for the docs-consistency PR that named the primitive.
Proposed change
One of:
iat(issued-at timestamp, integer seconds since epoch).nonce(echo of the request's idempotency key or a request-bound identifier —claim_id+ caller identity is the natural choice for verify_brand_claim).iatoutside an implementation-declared freshness window AND MUST reject duplicate(nonce, kid)pairs within the window.max-ageas untrusted regardless of signature."Option 1 is the correct shape protocol-wise. Option 2 is a defensible holding pattern if implementers have already shipped envelopes that can't accommodate new required fields.
Acceptance
iatandnoncerules; conformance fixtures for both positive (fresh) and negative (stale, replayed) cases.verify_brand_claim.mdx#trust-modeland a follow-up to revisit at 4.0.Out of scope