Skip to content

fix(security): timestamp-bound V2 signature for generic webhook routes (#58461 salvage) - #58508

Merged
teknium1 merged 2 commits into
mainfrom
salvage/webhook-v2-signature
Jul 5, 2026
Merged

fix(security): timestamp-bound V2 signature for generic webhook routes (#58461 salvage)#58508
teknium1 merged 2 commits into
mainfrom
salvage/webhook-v2-signature

Conversation

@teknium1

@teknium1 teknium1 commented Jul 4, 2026

Copy link
Copy Markdown
Contributor

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)
  • Tests incl. forged-timestamp, replay-window, and V1-pinning cases

Validation

Before After
replayed captured request accepted forever rejected outside ±300s
GitHub/GitLab/Svix routes unchanged unchanged
existing V1 senders work work + one-time deprecation warning

Targeted suite: tests/gateway/test_webhook_adapter.py — 75 tests, all pass.

Closes #58461.

Infographic

webhook-v2-signature

@alt-glitch alt-glitch added type/security Security vulnerability or hardening comp/gateway Gateway runner, session dispatch, delivery platform/webhook Webhook / API server P2 Medium — degraded but workaround exists needs-repro Bug needs reproduction steps sweeper:risk-security-boundary Sweeper risk: may affect sandboxing, auth, credentials, or sensitive data labels Jul 4, 2026
@alt-glitch

Copy link
Copy Markdown
Collaborator

This was generated by AI during triage.

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 gateway/platforms/webhook.py).

Triaged as defense-in-depth replay hardening (P2 + needs-repro, type/security kept): the generic webhook route is HMAC-secret-gated and the replay requires the attacker to first capture a legitimate signed delivery, and no reproducible unauthorized-external-party PoC is attached, so it does not meet the SECURITY.md 3.1 escalation bar for P0/P1.

@egilewski

Copy link
Copy Markdown
Contributor

suggesting changes

I found one remaining replay bypass at the generic webhook signature boundary: gateway/platforms/webhook.py still enters timestamp-bound V2 validation only when both X-Webhook-Signature-V2 and X-Webhook-Timestamp are present, so a captured migration request carrying both signatures can be replayed by deleting X-Webhook-Timestamp and falling through to the legacy body-only V1 check.

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 X-Webhook-Signature-V2 plus a valid legacy signature when the timestamp header is removed.

The fix should treat the presence of X-Webhook-Signature-V2 as selecting V2 mode: require X-Webhook-Timestamp, reject missing or malformed V2 timestamp data, and reserve legacy V1 validation for requests that do not send V2 at all.

Signed: GPT-5.5-xhigh in Codex

@MorAlekss

Copy link
Copy Markdown
Contributor

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!
And thanks for the salvage, @teknium1!

MorAlekss and others added 2 commits July 5, 2026 01:31
- 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.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/gateway Gateway runner, session dispatch, delivery needs-repro Bug needs reproduction steps P2 Medium — degraded but workaround exists platform/webhook Webhook / API server sweeper:risk-security-boundary Sweeper risk: may affect sandboxing, auth, credentials, or sensitive data type/security Security vulnerability or hardening

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants