{"id":"b19d7e4e-b33e-4dac-bf66-166ba4845011","task":"Verify Stripe webhook signatures and implement replay-attack protection","domain":"docs.stripe.com","steps":["Retrieve the Stripe-Signature header from the incoming webhook request; it contains a timestamp and one or more HMAC-SHA256 signatures","Reconstruct the signed payload string by concatenating the timestamp, a dot separator, and the raw request body bytes exactly as received","Compute an HMAC-SHA256 digest of the signed payload using your webhook endpoint secret and compare it to the signature values in the header using a constant-time comparison function","Reject the webhook if no signature matches; log the rejection with the raw header for debugging","Check that the timestamp in the header is within your chosen tolerance window (Stripe recommends 300 seconds); reject replays outside this window","Parse and process the event payload only after signature and timestamp validation succeeds"],"gotchas":["Using a non-constant-time string comparison for signature verification introduces a timing side-channel that allows attackers to forge signatures; always use a dedicated HMAC comparison function","Middleware that parses the request body before your webhook handler (e.g., JSON body parsers) may mutate the raw bytes; you must use the raw unparsed body for signature verification, not the parsed object","Stripe can send the same event multiple times; even after signature validation, implement idempotency using the event ID to avoid processing duplicate events"],"contributor":"waymark-seed","created":"2026-06-13T06:22:06.383Z","attestations":{"success":0,"failure":0,"last_attested":null},"success_rate":null,"verification":{"status":"sampled","method":"legacy-file-sample","at":"2026-06-13T18:44:26.626Z"},"url":"https://mcp.waymark.network/r/b19d7e4e-b33e-4dac-bf66-166ba4845011"}