feat(webhook-triggers-app): address security concerns - #62
Open
alex-petrunin wants to merge 3 commits into
Open
Conversation
Each webhook URL can now carry its own independent secret using an inline format in the existing textarea fields: https://n8n.example.com/webhook token_a https://slack.com/services/xxx token_b Previously a single shared webhookToken was sent to every endpoint. A compromise at any one recipient exposed all others. Changes: - New url+token line format: split on first whitespace, token is optional - parseWebhookEntries() is the new core parse primitive; parseWebhookUrls delegates to it (backward-compatible wrapper) - getWebhookEntries() is the new core combine/dedup function; getWebhookUrls delegates to it (backward-compatible wrapper) - sendWebhooks() resolves token per-entry: inline token takes priority, falls back to global webhookToken, skips the entry if neither is set - Runtime deprecation warning fires when 2+ URLs share the global fallback - webhookToken made optional in settings.json (existing deployments continue to work unchanged via fallback) - All textarea descriptions updated with inline-token format docs
…okens and enforce minimum length in settings - Updated `workflow-http.js` to log security warnings for inline tokens below the recommended length. - Added `minLength` constraint (32) to `webhookToken` in settings schema.
alex-petrunin
force-pushed
the
JT-95028-Webhook-Triggers-App-single-shared-token
branch
from
May 4, 2026 13:41
a1390fa to
7af380f
Compare
…licating webhook entries
Copilot started reviewing on behalf of
Andrey Skladchikov (andrey-skl)
May 6, 2026 10:10
View session
Andrey Skladchikov (andrey-skl)
approved these changes
May 6, 2026
Contributor
There was a problem hiding this comment.
Pull request overview
This PR updates the webhook-triggers workflow utilities to support per-endpoint secrets by allowing an optional inline token next to each webhook URL, reducing the blast radius of a single recipient compromise while preserving backward compatibility via a global fallback token.
Changes:
- Added a new parsing primitive (
parseWebhookEntries) and a new combine/dedup primitive (getWebhookEntries), with existing URL-only helpers delegating to them. - Updated
sendWebhooks()to resolve an effective token per entry (inline token first, otherwise global fallback), skipping entries with no token and emitting a deprecation warning when multiple URLs share the global fallback. - Updated project settings schema/docs and expanded Vitest coverage for parsing, deduping, and token dispatch behavior.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
| packages/webhook-triggers-app/src/workflows/workflow-http.js | Adds entry parsing + dedup helpers and updates dispatch to use per-entry tokens with fallback + warnings. |
| packages/webhook-triggers-app/src/workflows/workflow-core.js | Re-exports the new helpers from the core module. |
| packages/webhook-triggers-app/src/workflows/tests/workflow-http.test.js | Adds tests for entry parsing, dedup behavior, and token selection/dispatch. |
| packages/webhook-triggers-app/src/settings.json | Makes webhookToken optional, enforces minLength, and updates UI descriptions to document inline token format. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
+177
to
+181
| console.log('[webhooks] Sending webhooks to ' + allEntries.length + ' URL(s)'); | ||
|
|
||
| var fallbackCount = 0; | ||
| allEntries.forEach(function(entry) { | ||
| var effectiveToken = entry.token != null ? entry.token : globalToken; |
Comment on lines
8
to
15
| "webhookToken": { | ||
| "title": "Webhook token", | ||
| "description": "The webhook token is a shared secret included in requests to all webhook URLs configured in this project. Only add endpoints you trust. Rotate this token immediately if any recipient is decommissioned or a compromise is suspected. Must be at least 32 characters long.", | ||
| "title": "Default webhook token", | ||
| "description": "Used for any webhook URL that does not have its own token. If multiple URLs rely on this default token, they all use the same secret, so if one is compromised, the others are too. For better security, add a token to each URL instead, for example: https://example.com mytoken", | ||
| "type": "string", | ||
| "format": "secret", | ||
| "x-scope": "PROJECT" | ||
| "x-scope": "PROJECT", | ||
| "minLength": 32 | ||
| }, |
Comment on lines
24
to
29
| "webhooksOnIssueCreated": { | ||
| "title": "Issue created", | ||
| "description": "Triggered when a new issue is created", | ||
| "description": "Triggered when a new issue is created. Enter one URL per line or separate multiple URLs with commas. To use a token for a specific webhook, add it after the URL, separated by a space. For example: https://example.com/hook mytoken", | ||
| "type": "string", | ||
| "format": "textarea", | ||
| "x-scope": "PROJECT" |
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.
Each webhook URL can now carry its own independent secret using an inline format in the existing textarea fields:
https://n8n.example.com/webhook token_a
https://slack.com/services/xxxxxxx token_b
Previously a single shared webhookToken was sent to every endpoint. A compromise at any one recipient exposed all others.
Changes: