fix(security): timestamp-bound V2 signature for generic webhook routes (#58461 salvage) - #58508
Conversation
Salvage of #58461 (@MorAlekss) onto current main with authorship preserved -- related, not a duplicate. Same webhook-signature family as #47849 (Standard Webhooks, which also binds a timestamp on Triaged as defense-in-depth replay hardening (P2 + needs-repro, |
|
suggesting changes I found one remaining replay bypass at the generic webhook signature boundary: The focused webhook suite passed with 75 tests, valid V2 requests still verify, present malformed timestamps are rejected, and the targeted downgrade probe confirmed the PR head still accepts The fix should treat the presence of Signed: GPT-5.5-xhigh in Codex |
|
Follow-up on my #58461 this salvage is based on an earlier commit and doesn't include a fix I added afterward. The gap I fixed: if a request carries both the V1 and V2 signatures (which happens when a sender is mid-migration to V2), stripping the X-Webhook-Timestamp header makes validation fall through to the unprotected legacy V1 check instead of rejecting the request. A V2-protected request gets silently downgraded to V1's protection level, reopening the exact replay vulnerability V2 was meant to close. Worth pulling in that commit before merging. Thanks for catching this, @egilewski! |
- warn once per route instead of on every request (busy senders would spam the log) - document X-Webhook-Signature-V2 / X-Webhook-Timestamp in the webhooks user guide Follow-ups for salvaged #58461.
14e2386 to
a39d9e2
Compare
Summary
The generic webhook route gains replay protection: a V2 signature (
X-Webhook-Signature-V2= HMAC-SHA256 of<timestamp>.<body>, ±300s window) closes the hole where a captured (body, signature) pair could be replayed forever against the V1 body-only HMAC. V1 stays accepted for backward compatibility with a once-per-route deprecation warning.Salvages #58461 by @MorAlekss onto current main, authorship preserved.
Changes
gateway/platforms/webhook.py: V2 timestamp-bound verification (constant-time compare, Svix-convention ±300s window); V1 kept, deprecation warning rate-limited to once per route (follow-up — the original warned on every request)website/docs/user-guide/messaging/webhooks.md: document V2/V1 signature schemes (follow-up)Validation
Targeted suite: tests/gateway/test_webhook_adapter.py — 75 tests, all pass.
Closes #58461.
Infographic