Skip to content

Signature requirement is triggered by a nested payload field, contradicting 3.2's "policy before body parsing" rule #7563

Description

@KonstantinMirin

Summary

The requirement to sign a request is triggered by the presence of a nested field inside the request payload. This makes a transport-security decision a function of application-payload semantics at arbitrary depth, and it is the one remaining place where verifier policy cannot be selected before the body is parsed.

AdCP 3.2 established the opposite principle elsewhere in the same document, and the spec already documents the better design for this specific case — so this is a request to finish a migration that is mostly already built, not a new design.

The rule today

docs/building/by-layer/L1/security.mdx (at dc4a454b3):

  • :69 — a buyer opts into the legacy HMAC-SHA256 webhook scheme by populating authentication.credentials at any of four nested locations: push_notification_config, accounts[].notification_configs[], sync_principal.configuration.notification_configs[], sync_agent_notification_configs.notification_configs[].
  • :1537 — the error taxonomy makes a signature mandatory when "request payload carries a field that triggers signing regardless of required_for membership".

So a verifier must read nested payload fields to learn whether the request it is reading was required to be signed.

Note the surface has grown: at v3.1.1 there were two trigger locations; there are now four.

Why this is worth changing

1. It contradicts the principle 3.2 just established. :1469 states that "the endpoint's trusted configuration and negotiated capability select this policy before body parsing or dispatch", and that an operation name or JSON-RPC method inside an unbound body must not drive verifier policy. That reasoning is correct and the webhook-credential escalation is the remaining exception to it.

2. The spec already recommends the replacement. :1631 — "Buyers SHOULD negotiate HMAC-mode out-of-band at onboarding … Durable per-counterparty mode selection in operator records is not MITM-mutable the way a per-request field is."

3. The negotiation surface now exists. 3.2 added legacy_hmac_fallback (:1583) with false documented as the recommended posture. The capability channel this rule needs is already shipped.

The escalation rule at :1537 exists to contain a threat created by expressing the preference in the body in the first place (:1630 — an on-path mutator can strip or inject the block). Removing the per-request trigger removes the threat rather than containing it.

Proposal

Make webhook-signing mode a negotiated, per-counterparty property rather than a per-request payload field:

  1. legacy_hmac_fallback plus the seller's onboarding record become the authoritative selector for HMAC vs 9421 webhook signing.
  2. Deprecate the per-request authentication block as a mode trigger on the 3.x timeline it already has (removed in 4.0).
  3. Once mode no longer comes from the payload, drop the signature escalation at :1537 entirely — it has nothing left to protect.

This is backwards-compatible as a 3.x deprecation: sellers that already set legacy_hmac_fallback: false are unaffected.

Alternative

If the per-request trigger must stay, it would help implementers to state explicitly that a conforming verifier is required to parse the request body before it can determine whether a signature was required, and to say how that interacts with the :1469 "policy before body parsing" rule. Right now the two read as incompatible and implementers have to guess which governs.


Found while implementing a 3.1.1 verifier; re-verified against main at dc4a454b3 before filing.

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

    claude-triagedIssue has been triaged by the Claude Code triage routine. Remove to re-triage.governanceIssue concerns the governance protocol domainneeds-wg-reviewBlocked on a working-group decision — surface in WG meeting agendasrfcProtocol change — auto-adds to roadmap board

    Type

    No type

    Projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions