Skip to content

Commit 9b246ba

Browse files
committed
revert(webhooks): undo trigger auth hardening pending compat plan
Reverts the Telegram inbound-token verification (3ed97a4, 41f133a) and the HMAC fail-closed change (5b6cae9). Production data shows ~79 live webhooks have no signing secret configured (63 GitHub, 9 Fireflies, 3 Jira, 2 Circleback, 1 Confluence, 1 Cal.com), so failing closed would 401 them. Restoring fail-open behavior until a backwards-compatible rollout (grandfather existing secretless webhooks / migration) is designed. Other security fixes on this branch are unaffected.
1 parent 536af73 commit 9b246ba

14 files changed

Lines changed: 27 additions & 201 deletions

File tree

apps/sim/app/api/webhooks/trigger/[path]/route.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -111,11 +111,6 @@ async function handleWebhookPost(
111111
const responses: NextResponse[] = []
112112

113113
for (const { webhook: foundWebhook, workflow: foundWorkflow } of webhooksForPath) {
114-
const reachabilityResponse = handleProviderReachabilityTest(foundWebhook, body, requestId)
115-
if (reachabilityResponse) {
116-
return reachabilityResponse
117-
}
118-
119114
const authError = await verifyProviderAuth(
120115
foundWebhook,
121116
foundWorkflow,
@@ -131,6 +126,11 @@ async function handleWebhookPost(
131126
return authError
132127
}
133128

129+
const reachabilityResponse = handleProviderReachabilityTest(foundWebhook, body, requestId)
130+
if (reachabilityResponse) {
131+
return reachabilityResponse
132+
}
133+
134134
const preprocessResult = await checkWebhookPreprocessing(foundWorkflow, foundWebhook, requestId)
135135
if (preprocessResult.error) {
136136
if (webhooksForPath.length > 1) {

apps/sim/lib/webhooks/providers/github.ts

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -48,12 +48,7 @@ export const githubHandler: WebhookProviderHandler = {
4848
verifyAuth({ request, rawBody, requestId, providerConfig }: AuthContext) {
4949
const secret = providerConfig.webhookSecret as string | undefined
5050
if (!secret) {
51-
logger.warn(
52-
`[${requestId}] GitHub webhook missing webhookSecret in providerConfig — rejecting request`
53-
)
54-
return new NextResponse('Unauthorized - GitHub signing secret not configured', {
55-
status: 401,
56-
})
51+
return null
5752
}
5853

5954
const signature =

apps/sim/lib/webhooks/providers/intercom.ts

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -49,12 +49,7 @@ export const intercomHandler: WebhookProviderHandler = {
4949
verifyAuth({ request, rawBody, requestId, providerConfig }: AuthContext) {
5050
const secret = providerConfig.webhookSecret as string | undefined
5151
if (!secret) {
52-
logger.warn(
53-
`[${requestId}] Intercom webhook missing webhookSecret in providerConfig — rejecting request`
54-
)
55-
return new NextResponse('Unauthorized - Intercom signing secret not configured', {
56-
status: 401,
57-
})
52+
return null
5853
}
5954

6055
const signature = request.headers.get('X-Hub-Signature')

apps/sim/lib/webhooks/providers/telegram.test.ts

Lines changed: 0 additions & 93 deletions
This file was deleted.

apps/sim/lib/webhooks/providers/telegram.ts

Lines changed: 6 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,6 @@
11
import { db, webhook, workflowDeploymentVersion } from '@sim/db'
22
import { createLogger } from '@sim/logger'
3-
import { safeCompare } from '@sim/security/compare'
4-
import { generateId } from '@sim/utils/id'
53
import { and, eq, isNull, ne } from 'drizzle-orm'
6-
import * as ipaddr from 'ipaddr.js'
7-
import { NextResponse } from 'next/server'
8-
import { getClientIp } from '@/lib/core/utils/request'
94
import { getNotificationUrl, getProviderConfig } from '@/lib/webhooks/provider-subscription-utils'
105
import type {
116
AuthContext,
@@ -19,63 +14,14 @@ import type {
1914

2015
const logger = createLogger('WebhookProvider:Telegram')
2116

22-
/**
23-
* Telegram's published source ranges for webhook delivery.
24-
* @see https://core.telegram.org/bots/webhooks
25-
*/
26-
const TELEGRAM_WEBHOOK_CIDRS: ReadonlyArray<readonly [string, number]> = [
27-
['149.154.160.0', 20],
28-
['91.108.4.0', 22],
29-
] as const
30-
31-
/** Whether a client IP falls inside Telegram's documented webhook source ranges. */
32-
function isTelegramWebhookIp(ip: string): boolean {
33-
if (!ip || ip === 'unknown' || !ipaddr.isValid(ip)) {
34-
return false
35-
}
36-
try {
37-
const addr = ipaddr.process(ip)
38-
if (addr.kind() !== 'ipv4') {
39-
return false
40-
}
41-
return TELEGRAM_WEBHOOK_CIDRS.some(([network, prefix]) =>
42-
addr.match([ipaddr.parse(network), prefix])
43-
)
44-
} catch {
45-
return false
46-
}
47-
}
48-
4917
export const telegramHandler: WebhookProviderHandler = {
50-
verifyAuth({ request, requestId, providerConfig }: AuthContext): NextResponse | null {
51-
const secretToken = (providerConfig.secretToken as string | undefined)?.trim()
52-
53-
if (secretToken) {
54-
const providedToken = request.headers.get('x-telegram-bot-api-secret-token')
55-
if (!providedToken) {
56-
logger.warn(
57-
`[${requestId}] Telegram webhook missing secret token header — rejecting request`
58-
)
59-
return new NextResponse('Unauthorized - Missing Telegram secret token', { status: 401 })
60-
}
61-
62-
if (!safeCompare(providedToken, secretToken)) {
63-
logger.warn(`[${requestId}] Telegram secret token verification failed`)
64-
return new NextResponse('Unauthorized - Invalid Telegram secret token', { status: 401 })
65-
}
66-
67-
return null
68-
}
69-
70-
const clientIp = getClientIp(request)
71-
if (!isTelegramWebhookIp(clientIp)) {
18+
verifyAuth({ request, requestId }: AuthContext) {
19+
const userAgent = request.headers.get('user-agent')
20+
if (!userAgent) {
7221
logger.warn(
73-
`[${requestId}] Telegram webhook without a registered secret token rejected — source IP is not in Telegram's published ranges. Re-save the trigger to enable secret-token verification.`,
74-
{ clientIp }
22+
`[${requestId}] Telegram webhook request has empty User-Agent header. This may be blocked by middleware.`
7523
)
76-
return new NextResponse('Unauthorized - Untrusted Telegram webhook source', { status: 401 })
7724
}
78-
7925
return null
8026
},
8127

@@ -179,17 +125,14 @@ export const telegramHandler: WebhookProviderHandler = {
179125
const notificationUrl = getNotificationUrl(ctx.webhook)
180126
const telegramApiUrl = `https://api.telegram.org/bot${botToken}/setWebhook`
181127

182-
const existingSecretToken = (config.secretToken as string | undefined)?.trim()
183-
const secretToken = existingSecretToken || generateId()
184-
185128
try {
186129
const telegramResponse = await fetch(telegramApiUrl, {
187130
method: 'POST',
188131
headers: {
189132
'Content-Type': 'application/json',
190133
'User-Agent': 'TelegramBot/1.0',
191134
},
192-
body: JSON.stringify({ url: notificationUrl, secret_token: secretToken }),
135+
body: JSON.stringify({ url: notificationUrl }),
193136
})
194137

195138
const responseBody = await telegramResponse.json()
@@ -213,7 +156,7 @@ export const telegramHandler: WebhookProviderHandler = {
213156
logger.info(
214157
`[${ctx.requestId}] Successfully created Telegram webhook for webhook ${ctx.webhook.id}`
215158
)
216-
return { providerConfigUpdates: { secretToken } }
159+
return {}
217160
} catch (error: unknown) {
218161
if (
219162
error instanceof Error &&

apps/sim/lib/webhooks/providers/utils.ts

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,6 @@ interface HmacVerifierOptions {
1616
/**
1717
* Factory that creates a `verifyAuth` implementation for HMAC-signature-based providers.
1818
* Covers the common pattern: get secret → check header → validate signature → return 401 or null.
19-
*
20-
* Fails closed: when no signing secret is configured the request is rejected (401), matching
21-
* Stripe/WhatsApp/Vercel. A signed-provider webhook with no secret would otherwise accept any
22-
* unauthenticated body that knows the URL, downgrading the provider's mandatory signature check.
2319
*/
2420
export function createHmacVerifier({
2521
configKey,
@@ -35,12 +31,7 @@ export function createHmacVerifier({
3531
}: AuthContext): Promise<NextResponse | null> => {
3632
const secret = providerConfig[configKey] as string | undefined
3733
if (!secret) {
38-
logger.warn(
39-
`[${requestId}] ${providerLabel} webhook missing signing secret in providerConfig — rejecting request`
40-
)
41-
return new NextResponse(`Unauthorized - ${providerLabel} signing secret not configured`, {
42-
status: 401,
43-
})
34+
return null
4435
}
4536

4637
const signature = request.headers.get(headerName)

apps/sim/triggers/circleback/webhook.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,8 @@ export const circlebackWebhookTrigger: TriggerConfig = {
3838
id: 'webhookSecret',
3939
title: 'Signing Secret',
4040
type: 'short-input',
41-
placeholder: 'Paste signing secret from Circleback',
42-
description:
43-
'Validates that webhook deliveries originate from Circleback using HMAC-SHA256. Required: deliveries are rejected until this is set.',
41+
placeholder: 'Paste signing secret from Circleback (optional)',
42+
description: 'Validates that webhook deliveries originate from Circleback using HMAC-SHA256.',
4443
password: true,
4544
required: false,
4645
mode: 'trigger',

apps/sim/triggers/confluence/utils.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ export function buildConfluenceExtraFields(triggerId: string): SubBlockConfig[]
5454
type: 'short-input',
5555
placeholder: 'Enter a strong secret',
5656
description:
57-
'Secret to validate webhook deliveries from Confluence using HMAC signature. Required: deliveries are rejected until this is set.',
57+
'Optional secret to validate webhook deliveries from Confluence using HMAC signature',
5858
password: true,
5959
required: false,
6060
mode: 'trigger',

apps/sim/triggers/fireflies/transcription_complete.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,7 @@ export const firefliesTranscriptionCompleteTrigger: TriggerConfig = {
2525
title: 'Webhook Secret',
2626
type: 'short-input',
2727
placeholder: 'Enter your 16-32 character secret',
28-
description:
29-
'Secret key for HMAC signature verification (set in Fireflies dashboard). Required: deliveries are rejected until this is set.',
28+
description: 'Secret key for HMAC signature verification (set in Fireflies dashboard)',
3029
password: true,
3130
required: false,
3231
mode: 'trigger',

apps/sim/triggers/github/webhook.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,7 @@ export const githubWebhookTrigger: TriggerConfig = {
4646
title: 'Webhook Secret',
4747
type: 'short-input',
4848
placeholder: 'Generate or enter a strong secret',
49-
description:
50-
'Validates that webhook deliveries originate from GitHub. Required: deliveries are rejected until this is set.',
49+
description: 'Validates that webhook deliveries originate from GitHub.',
5150
password: true,
5251
required: false,
5352
mode: 'trigger',

0 commit comments

Comments
 (0)