Problem
The webhook envelope spec in `specs/registry-change-feed.md` signs only the request body with HMAC. There's no timestamp and no delivery sequence in the signed material. A captured webhook can be replayed indefinitely (same body, same signature, same `latest_event_id`).
Surfaced during security review of the catalog change feed — same gap exists upstream. The catalog feed spec already adopts the fix (see commit 3f32784); this issue tracks porting it to the registry feed.
Proposed fix
Mirror the catalog-feed shape from PR #4767:
```
POST https://buyer.example.com/hooks/registry
X-Registry-Signature: sha256={hmac}
X-Registry-Event: property.created
X-Registry-Timestamp: 2026-05-19T11:00:00Z
X-Registry-Delivery-Seq: 4421
```
- HMAC is computed over the canonical string `{timestamp}\n{delivery_seq}\n{body}` (newline-separated).
- Receivers MUST reject signatures whose timestamp is more than 5 minutes skewed from receive time.
- `delivery_seq` is strictly monotonic per subscription. Receivers de-dupe on `(subscription_id, delivery_seq)`.
- Retried deliveries reuse the original `delivery_seq` — receivers dedupe on the sequence, not the signature.
Scope
Compatibility
Adding new signed headers is breaking for existing subscribers (the signature they verify is over a different string). Two paths:
- Versioned signer: ship a new `X-Registry-Signer-Version: 2` header; v1 signers continue to compute over body-only for a deprecation window. Subscribers honor whichever they receive.
- Coordinated cut: announce date, switch all subscribers in one window. Easier for the central registry where there's a single operator.
Lean toward (1) for safety. The registry feed has external subscribers (TMP routers, RegistrySync clients) that can't all be coordinated.
Related
Problem
The webhook envelope spec in `specs/registry-change-feed.md` signs only the request body with HMAC. There's no timestamp and no delivery sequence in the signed material. A captured webhook can be replayed indefinitely (same body, same signature, same `latest_event_id`).
Surfaced during security review of the catalog change feed — same gap exists upstream. The catalog feed spec already adopts the fix (see commit 3f32784); this issue tracks porting it to the registry feed.
Proposed fix
Mirror the catalog-feed shape from PR #4767:
```
POST https://buyer.example.com/hooks/registry
X-Registry-Signature: sha256={hmac}
X-Registry-Event: property.created
X-Registry-Timestamp: 2026-05-19T11:00:00Z
X-Registry-Delivery-Seq: 4421
```
Scope
Compatibility
Adding new signed headers is breaking for existing subscribers (the signature they verify is over a different string). Two paths:
Lean toward (1) for safety. The registry feed has external subscribers (TMP routers, RegistrySync clients) that can't all be coordinated.
Related