{
  "id": 11687520,
  "title": "Why your webhook signature check fails (and the bugs that pass it)",
  "url": "https://urgent.news/2026/10/03/why-your-webhook-signature-check-fails-and-the-bugs-that-pass-it",
  "topic": "tech",
  "section": "Tech",
  "published": "2026-10-03T13:07:05.000Z",
  "source": {
    "name": "Dev.to",
    "slug": "dev-to",
    "url": "https://dev.to/creatorpiyush/why-your-webhook-signature-check-fails-and-the-bugs-that-pass-it-10fo"
  },
  "original_language": "en",
  "account": "In July, the author built verihook due to the diverse way providers sign webhooks, which led to the creation of five distinct HMAC functions that needed continuous maintenance. Over time, verihook grew to support 40+ providers, ten frameworks, testing helpers, and a documentation site. Despite being primarily focused on the HMAC, the author discovered that many verification issues stem from other aspects such as the body, secret, URL, retries, and tests.\n\nThe primary mistakes the author observed in webhook verification include:\n\n1. The body parser modifying the signature: Providers sign the exact bytes sent. However, functions like JSON.stringify(JSON.parse(body)) can alter whitespace, escape characters, and number formatting. To avoid this, use raw body parsers such as express.raw(), await request.text(), Fastify's rawBody, or NestJS's rawBody: true. verihook can detect such issues, as it identifies when the body size doesn't match the content-length, which usually indicates the body has been parsed and re-serialized.\n\n2. Using the wrong secret: Common errors include using an API key instead of the endpoint's signing secret or using the test-mode secret in production. Slack bot tokens, trailing newlines, or quotes from the .env file can also result in signature mismatches. verihook recognizes these mistakes by analyzing the shape of the secret and providing a hint indicating the specific error.\n\n3. Proxy altering the URL: Services like Twilio, Square, and HubSpot sign the public URL they called. When the server is behind an ngrok, load balancer, or API Gateway, it receives a different URL (e.g., http://10.0.0.5:3000/... instead of https://api.example.com/...). To resolve this, rebuild the URL from x-forwarded-proto and x-forwarded-host or explicitly pass the public URL during verification.\n\n4. Duplicate webhook processing: Providers typically retry at least once if there's a timeout, and a valid signature accepts all copies. To prevent this, implement deduplication using a key that includes data covered by the signature (for example, a signed ID header, an ID inside the signed body, or a hash of the body). In the case of GitHub, using x-github-delivery as a dedupe key can lead to an attacker replaying a captured webhook and bypassing the dedupe store. verihook only keys on data covered by the signature, such as a signed ID header or a hash of the body.\n\n5. Relying on tests that test themselves: A classic example is when the verihook Paddle verifier uses the h= header in the Paddle-Signature header, while the test signer writes h=. Every test pass, but real Paddle webhooks are rejected as they send h1=. To avoid this, use known-good vectors from the provider's documentation, such as a payload, secret, and signature that you didn't compute yourself. Additionally, perform conformance tests against official SDKs, and leverage verihook's CI, which signs with official Stripe, Octokit, Svix, and Twilio SDKs and verifies with verihook, as well as the reverse. You can find examples in the verihook documentation, which includes a page for each provider detailing where to locate the secret in each dashboard.",
  "summary": "In July I wrote about why I built verihook : every provider signs webhooks differently, and I was tired of maintaining five slightly different HMAC functions. Since then verihook has grown to 40+ providers, adapters for ten frameworks, testing helpers and a docs site . Supporting that many providers taught me where webhook verification actually goes wrong. It's rarely the HMAC. It's everything…",
  "key_points": [
    "Body parser can modify the signature",
    "Wrong secret usage is common mistake",
    "Proxy can alter the URL during verification"
  ],
  "editors_take": null,
  "illustration": null,
  "coverage": {
    "outlets": 1,
    "also_reported_by": []
  },
  "ai_generated": true,
  "disclaimer": "Summaries, key points and the editor’s take are written by software from other outlets’ reporting and may contain errors — always check the linked original."
}