Files
sim/apps/sim/triggers/generic/webhook.ts
Waleed ff2a1527ab fix(security): add SSRF protection to database tools and webhook delivery (#3500)
* fix(security): add SSRF protection to database tools and webhook delivery

* fix(security): address review comments on SSRF PR

- Remove Promise.race timeout pattern to avoid unhandled rejections
  (http.request timeout is sufficient for webhook delivery)
- Use safeCompare in verifyCronAuth instead of inline HMAC logic
- Strip IPv6 brackets before validateDatabaseHost in Redis route

* fix(security): allow HTTP webhooks and fix misleading MCP error docs

- Add allowHttp option to validateExternalUrl, validateUrlWithDNS,
  and secureFetchWithValidation to support HTTP webhook URLs
- Pass allowHttp: true for webhook delivery and test endpoints
- Fix misleading JSDoc on createMcpErrorResponse (doesn't log errors)
- Mark unused error param with underscore prefix

* fix(security): forward allowHttp option through redirect validation

Pass allowHttp to validateUrlWithDNS in the redirect handler of
secureFetchWithPinnedIP so HTTP-to-HTTP redirects work when allowHttp
is enabled for webhook delivery.

* fix(security): block localhost when allowHttp is enabled

When allowHttp is true (user-supplied webhook URLs), explicitly block
localhost/loopback in both validateExternalUrl and validateUrlWithDNS
to prevent SSRF against internal services.

* fix(security): always strip multi-line content in sanitizeConnectionError

Take the first line of the error message regardless of length to
prevent leaking sensitive data from multi-line error messages.
2026-03-09 20:28:28 -07:00

99 lines
2.9 KiB
TypeScript

import { WebhookIcon } from '@/components/icons'
import type { TriggerConfig } from '@/triggers/types'
export const genericWebhookTrigger: TriggerConfig = {
id: 'generic_webhook',
name: 'Generic Webhook',
provider: 'generic',
description: 'Receive webhooks from any service or API',
version: '1.0.0',
icon: WebhookIcon,
subBlocks: [
{
id: 'webhookUrlDisplay',
title: 'Webhook URL',
type: 'short-input',
readOnly: true,
showCopyButton: true,
useWebhookUrl: true,
placeholder: 'Webhook URL will be generated',
mode: 'trigger',
},
{
id: 'requireAuth',
title: 'Require Authentication',
type: 'switch',
description: 'Require authentication for all webhook requests',
defaultValue: true,
mode: 'trigger',
},
{
id: 'token',
title: 'Authentication Token',
type: 'short-input',
placeholder: 'Enter an auth token',
description: 'Token used to authenticate webhook requests via Bearer token or custom header',
password: true,
required: false,
value: () => crypto.randomUUID(),
mode: 'trigger',
},
{
id: 'secretHeaderName',
title: 'Secret Header Name (Optional)',
type: 'short-input',
placeholder: 'X-Secret-Key',
description:
'Custom HTTP header name for the auth token. If blank, uses "Authorization: Bearer TOKEN"',
required: false,
mode: 'trigger',
},
{
id: 'inputFormat',
title: 'Input Format',
type: 'input-format',
description:
'Define the expected JSON input schema for this webhook (optional). Use type "file[]" for file uploads.',
mode: 'trigger',
},
{
id: 'triggerSave',
title: '',
type: 'trigger-save',
hideFromPreview: true,
mode: 'trigger',
triggerId: 'generic_webhook',
},
{
id: 'triggerInstructions',
title: 'Setup Instructions',
hideFromPreview: true,
type: 'text',
defaultValue: [
'Copy the webhook URL and use it in your external service or API.',
'Configure your service to send webhooks to this URL.',
'The webhook will receive any HTTP method (GET, POST, PUT, DELETE, etc.).',
'All request data (headers, body, query parameters) will be available in your workflow.',
'If authentication is enabled, include the token in requests using either the custom header or "Authorization: Bearer TOKEN".',
'Common fields like "event", "id", and "data" will be automatically extracted from the payload when available.',
]
.map(
(instruction, index) =>
`<div class="mb-3"><strong>${index + 1}.</strong> ${instruction}</div>`
)
.join(''),
mode: 'trigger',
},
],
outputs: {},
webhook: {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
},
}