feat(webhook_verify): timing-safe, replay-resistant webhook signature verification module (29 tests, zero deps) - #22
Merged
ralyodio merged 1 commit intoAug 19, 2026
Conversation
Adds a community module for the one piece of security code most backends rewrite and get
wrong. Supports Stripe (incl. multi-v1 secret rotation), GitHub, Slack, Shopify, Twilio and
generic hex HMAC.
Design rules, each covered by a test:
- every digest comparison goes through timingSafeEqual, with an explicit length check first
- replay windows on every provider that signs a timestamp, symmetric so future-dated
timestamps are rejected too
- verification runs against the raw body; nothing is parsed before the signature is checked
- failures return a specific reason (signature_mismatch / timestamp_out_of_range /
malformed_signature) instead of a bare false, so a falsy value cannot be mistaken for a
handled failure
Zero dependencies beyond node:crypto. 29 mocha/chai tests. Follows the template module
layout: index.js register(), src/{service,controller,utils}.js, test/, examples/, docs/.
Refs profullstack#2
| import { createHmac } from 'node:crypto'; | ||
| import { verify } from '../src/service.js'; | ||
|
|
||
| const SECRET = 'whsec_example'; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Refs #2 — you asked for more community packages, so here is one that fills a gap I did not see covered by the existing modules.
What it does
webhook_verifyverifies inbound webhook signatures for Stripe, GitHub, Slack, Shopify, Twilio and generic hex HMAC. Zero dependencies —node:cryptoonly.Why this one
Webhook verification is the security code almost every backend rewrites, and it fails in four predictable ways:
signature === expectedfalseif (verify(...))and a truthy value slips throughThe module inverts each one:
timingSafeEqualeverywhere, with an explicit length check first —timingSafeEqualthrows on unequal lengths, and length is itself a leakreason(signature_mismatch,timestamp_out_of_range,malformed_signature,unsupported_provider) plusadvice: "Do not parse or act on this payload."Stripe secret rotation is handled: a header carrying several
v1=values passes if any one matches.Layout
Follows
mcp_modules/templateexactly:Tests
29 passing (mocha + chai):
A failed verification returns HTTP 200 with
valid: false— it is a valid answer, not a server error. Missing or unsupported parameters return 400.Happy to rename the module, adjust the endpoint prefix, or split providers if you would rather they were separate modules.