Skip to content

fix(integration): correct ingress HMAC substitution and constant-time challenge compare#592

Merged
rmyndharis merged 1 commit into
mainfrom
fix/ingress-signature-correctness
Jul 2, 2026
Merged

fix(integration): correct ingress HMAC substitution and constant-time challenge compare#592
rmyndharis merged 1 commit into
mainfrom
fix/ingress-signature-correctness

Conversation

@rmyndharis

Copy link
Copy Markdown
Owner

Summary

Two correctness/hardening fixes on the inbound-webhook (ingress) verification path.

Changes

  • HMAC signed-content substitution. The signed string was built with template.replace('{rawBody}', rawBody).replace('{timestamp}', ts). String.prototype.replace with a string pattern only replaces the first occurrence and interprets $&, $\``, $', $$, $nin the replacement — which here is the attacker-controlled raw body. A provider that legitimately signed a body containing a$-sequence would have its signature rejected (silent inbound message loss). Replaced with a single-pass function replacer over /{rawBody}|{timestamp}/gthat inserts each value literally; because the body is substituted (not re-scanned), a{timestamp}` embedded in the body is never re-interpreted.
  • Constant-time challenge compare. The GET-challenge verify-token check used plain ===; switched to the existing constant-time safeEqualStr (now exported), matching the signature path and removing a timing oracle. The token && verifyToken && guards are preserved so a null token never matches.

Verification

npm run build ✓ · npm test ✓ (1852/1852, +3) · lint ✓. New tests: a body with $&/$'/$/$$/$1and a literal{timestamp}` verifies correctly (both single- and multi-token templates); a challenge with an empty/absent verify token is rejected.

… challenge compare

- Build the HMAC signed content with a single-pass function replacer instead of chained String.replace.
  The old code only replaced the first token and interpreted $&, $`, $', $$, $n in the replacement
  (the attacker-controlled raw body), so a legitimately-signed delivery whose body contained a
  $-sequence diverged from the provider's signed bytes and was silently rejected (inbound message loss).
- Compare the GET-challenge verify token with the existing constant-time safeEqualStr (now exported)
  instead of plain ===, matching the signature path and removing a timing oracle.
@rmyndharis rmyndharis merged commit 883937f into main Jul 2, 2026
3 checks passed
@rmyndharis rmyndharis deleted the fix/ingress-signature-correctness branch July 2, 2026 13:28
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.

1 participant