STRATCONN-2460: Webhook: sign full batch body for X-Signature header - #3989
Open
mdkhan-tw wants to merge 1 commit into
Open
STRATCONN-2460: Webhook: sign full batch body for X-Signature header#3989mdkhan-tw wants to merge 1 commit into
mdkhan-tw wants to merge 1 commit into
Conversation
Autonomously reproduced, fixed, and validated against the real destination. Ticket: STRATCONN-2460 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Contributor
There was a problem hiding this comment.
Warning
Copilot couldn't run its full agentic review because it didn't start before the timeout. Make sure your repository has a runner available, or add a copilot-code-review.yml file specifying one with the runs-on attribute. See the docs for more details.
Pull request overview
Updates the webhook destination signature calculation so X-Signature is computed over the exact request body when batching is enabled, aligning HMAC verification with what is actually sent.
Changes:
- Update
extendRequestto sign the full batch body (array of eventdata) instead of only the first event. - Add/adjust unit test to validate signature computation over the full batch payload.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| packages/destination-actions/src/destinations/webhook/index.ts | Adjusts HMAC input to match the real HTTP request body in batch vs single mode. |
| packages/destination-actions/src/destinations/webhook/test/webhook.test.ts | Updates test to assert the signature is computed over the full batch body. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| // its `data`. Sign the exact body that will be sent so the X-Signature HMAC | ||
| // matches whether or not batching is enabled. | ||
| const signedBody = Array.isArray(payload) ? payload.map((p) => p['data']) : payload['data'] | ||
| const hasBody = Array.isArray(payload) ? payload.length > 0 : Boolean(signedBody) |
Comment on lines
+27
to
+30
| const signedBody = Array.isArray(payload) ? payload.map((p) => p['data']) : payload['data'] | ||
| const hasBody = Array.isArray(payload) ? payload.length > 0 : Boolean(signedBody) | ||
| if (settings.sharedSecret && hasBody) { | ||
| const digest = createHmac('sha1', settings.sharedSecret).update(JSON.stringify(signedBody), 'utf8').digest('hex') |
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.
STRATCONN-2460 — Webhook: sign full batch body for X-Signature header
🎫 Ticket
x-signature missing in request header when batching is enabled | Webhook Actions (status: Done)
Destination:
webhook· Action:send· triage confidence: medium🔍 Root cause
In batch mode extendRequest signed the HMAC over only payload[0]['data'] while performBatch sends the full array of each event's data, so the X-Signature header didn't match the actual request body.
🧪 Reproduction — before the fix
Fired this event at the real destination:
[ { "type": "track", "event": "Event A", "userId": "user-a", "properties": { "n": 1 } }, { "type": "track", "event": "Event B", "userId": "user-b", "properties": { "n": 2 } } ]Mapping:
{ "url": "https://httpbin.org/anything", "method": "POST" }200X-Signaturesent:bdf01b9a45c02b1c74e6f955a02212b6e49d2d5e· expected over actual body:99df4a041ed8cab7d82dabbccda7764666b2b410→ MISMATCH ❌[{"type":"track","event":"Event A","userId":"user-a","properties":{"n":1}},{"type":"track","event":"Event B","userId":"user-b","properties":{"n":2}}]🛠 The fix
Changed files:
✅ Verification — local (isolated git worktree)
🔒 Validation — after the fix, real destination
Re-ran the exact same reproduction against the patched code:
200♻️ Regression coverage
A unit test in the destination's
__test__suite now asserts the corrected behavior — it fails on the buggy code and passes on the fix, so this can't silently regress../bin/run serve --destination webhook --noUI # POST the event above to http://127.0.0.1:3000/send🤖 Generated with Claude Code — reproduce → fix → verify → validate, fully automated. Please review before merging.