Skip to content

test(webhooks): add unit tests for verifyWebhookSignature timing-safe comparison - #674

Merged
Chucks1093 merged 1 commit into
accesslayerorg:mainfrom
Ajibose:test/webhook-signature-timing-safe-comparison
Jul 27, 2026
Merged

test(webhooks): add unit tests for verifyWebhookSignature timing-safe comparison#674
Chucks1093 merged 1 commit into
accesslayerorg:mainfrom
Ajibose:test/webhook-signature-timing-safe-comparison

Conversation

@Ajibose

@Ajibose Ajibose commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

Closes #666

Summary

Adds unit test coverage for the timing-safe signature comparison performed by verifyWebhookSignature, and adds the helper itself (HMAC-SHA256 verification of a sha256=<hex> webhook signature header using crypto.timingSafeEqual), since it did not yet exist in the codebase.

Files

New files

  • src/modules/webhooks/webhook-signature.utils.tsverifyWebhookSignature(payload, header, secret) helper. Parses the sha256=<hex> header format, computes the expected HMAC-SHA256 digest of the raw payload with the given secret, and compares it to the provided signature using crypto.timingSafeEqual for constant-time comparison. Returns false (rather than throwing) for missing headers, malformed headers, and length-mismatched signatures — the length check happens before timingSafeEqual is called, since that API throws on differing buffer lengths.
  • src/modules/webhooks/webhook-signature.utils.test.ts — unit tests for the helper (see below).

Modified files

  • None.

Implementation details

  • The signature header is expected in the form sha256=<hex-digest>, matched with /^sha256=([0-9a-f]+)$/i.
  • The expected signature is computed via crypto.createHmac('sha256', secret).update(payload).digest('hex').
  • Both the provided and expected signatures are compared as UTF-8 buffers. Their lengths are checked first and a mismatch short-circuits to false, avoiding the RangeError that crypto.timingSafeEqual throws when given buffers of unequal length.
  • Only if the lengths match does the function fall through to crypto.timingSafeEqual, which performs the actual constant-time comparison.

Tests added

All tests live in webhook-signature.utils.test.ts and use a real HMAC-SHA256 signature computed from a fixed test secret/payload as the baseline "valid" signature:

  • returns true for a valid signature — sanity check that a correctly computed signature verifies.
  • returns false when the signature differs in the last character — flips the final hex character of a valid signature and confirms it's rejected.
  • returns false when the signature differs in the first character — flips the first hex character after the sha256= prefix and confirms it's rejected.
  • returns false without throwing when the signature is one character shorter than expected — truncates the last character of a valid signature; asserts it neither throws nor verifies.
  • returns false without throwing when the signature is one character longer than expected — appends an extra character to a valid signature; asserts it neither throws nor verifies.
  • returns false without throwing for a malformed header — a header that doesn't match the sha256=<hex> pattern at all.
  • returns false for an empty header — empty string input.

How to test

npx jest src/modules/webhooks/webhook-signature.utils.test.ts

All 7 tests pass. Existing test suites are unaffected (no existing files were modified).

… comparison

Adds the verifyWebhookSignature helper (HMAC-SHA256, constant-time
comparison via crypto.timingSafeEqual) and unit test coverage for its
timing-safe comparison behavior, closing accesslayerorg#666:

- Signature differing in the last character returns false
- Signature differing in the first character returns false
- Signature one character shorter than expected returns false without throwing
- Signature one character longer than expected returns false without throwing
- Valid signature returns true
- Malformed/empty header returns false without throwing
@drips-wave

drips-wave Bot commented Jul 27, 2026

Copy link
Copy Markdown

@Ajibose Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits.

You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀

Learn more about application limits

@Chucks1093
Chucks1093 merged commit c027095 into accesslayerorg:main Jul 27, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add unit tests for verifyWebhookSignature helper covering timing-safe comparison behaviour

2 participants