Fix the webhook verifier for payment events
Your task
An AI implemented webhook signature checks for your payment provider. Valid webhooks verified and the tests passed, but the tests only ever sent valid webhooks. A webhook that is replayed, redelivered or tampered with is what this check exists for. Your team rewrote the decision with every rejection spelled out.
An assistant wrote verify_webhook(header, computed_sig, event_id, now_epoch, tolerance_seconds, seen_event_ids). It is in the editor. It has a bug. Find it and fix it.
Input and output:
header: the signature header, a comma-separated list ofkey=valueparts, liket=1700000000,v1=abc123.tis the send time in epoch seconds andv1is the signature.computed_sig: the signature your server computed over the raw request body.event_id: the event's id.now_epoch: the current time in epoch seconds.tolerance_seconds: how far aparttand now may be.seen_event_ids: the ids of events already processed.- Return
"malformed_header","stale_timestamp","bad_signature","replayed"or"accepted".
Rules the tests check. Return the first that applies:
"malformed_header": a part has no=, there is no non-emptytorv1, ortis not all digits from 0 to 9. Split each part at its first=, and trim nothing. When a key repeats, its first non-empty value counts. Other keys, such asv0, are ignored."stale_timestamp":tandnow_epochare more thantolerance_secondsapart, in either direction."bad_signature":v1is not exactlycomputed_sig. Compare in constant time, so the time taken does not reveal how much matched."replayed":event_idis inseen_event_ids.- Otherwise
"accepted".
Examples
verify_webhook(header: str, computed_sig: str, event_id: str, now_epoch: int, tolerance_seconds: int, seen_event_ids: list[str]) -> strExample 1
Input
verify_webhook("t=1700000000,v1=abc123", "abc123", "evt_1", 1700000010, 300, [])Output
"accepted"Example 2
Input
verify_webhook("t=1700000000,v1=abc123", "abc999", "evt_2", 1700000010, 300, [])Output
"bad_signature"Example 3
Input
verify_webhook("t=1700000000,v1=abc123", "abc123", "evt_3", 1700000600, 300, [])Output
"stale_timestamp"