Context
verifyWebhookWithReplay in src/webhooks.ts only rejects a signed header when Date.now() - timestamp > toleranceMs; a header whose t= value lies in the future produces a negative age that always passes, and parseWebhookHeader accepts any integer it can parse. A far-future t= combined with a valid HMAC therefore verifies as true, and no allowance is made for clock skew between the sender and the verifier.
Proposed Change
Reject timestamps that fall outside the window [-toleranceMs, +toleranceMs] so small negative skew is tolerated but future-dated signatures are refused, and validate that toleranceMs is a positive finite number.
Acceptance Criteria
Suggested Label
bug
ETA: 24 hours
Context
verifyWebhookWithReplayinsrc/webhooks.tsonly rejects a signed header whenDate.now() - timestamp > toleranceMs; a header whoset=value lies in the future produces a negative age that always passes, andparseWebhookHeaderaccepts any integer it can parse. A far-futuret=combined with a valid HMAC therefore verifies as true, and no allowance is made for clock skew between the sender and the verifier.Proposed Change
Reject timestamps that fall outside the window
[-toleranceMs, +toleranceMs]so small negative skew is tolerated but future-dated signatures are refused, and validate thattoleranceMsis a positive finite number.Acceptance Criteria
t = Date.now() + 600_000and a correctly signed payload returnsfalsetoleranceMsand +/-toleranceMs + 1tests/webhook-verification.test.tsstill passSuggested Label
bug
ETA: 24 hours