From db4b36297df8ac7c5f0def6f8d09ff2d2b03b99c Mon Sep 17 00:00:00 2001 From: waleed Date: Sat, 13 Dec 2025 19:39:49 -0800 Subject: [PATCH] fix(tools): add validation for ids in tool routes --- apps/sim/app/api/proxy/tts/unified/route.ts | 5 +++++ apps/sim/app/api/tools/discord/send-message/route.ts | 12 ++++++++++++ apps/sim/app/api/tools/webflow/collections/route.ts | 8 +++++--- apps/sim/app/api/tools/webflow/items/route.ts | 8 +++++--- 4 files changed, 27 insertions(+), 6 deletions(-) diff --git a/apps/sim/app/api/proxy/tts/unified/route.ts b/apps/sim/app/api/proxy/tts/unified/route.ts index 9937a513a3..827dfae61c 100644 --- a/apps/sim/app/api/proxy/tts/unified/route.ts +++ b/apps/sim/app/api/proxy/tts/unified/route.ts @@ -1,6 +1,7 @@ import type { NextRequest } from 'next/server' import { NextResponse } from 'next/server' import { checkHybridAuth } from '@/lib/auth/hybrid' +import { validateAlphanumericId } from '@/lib/core/security/input-validation' import { getBaseUrl } from '@/lib/core/utils/urls' import { createLogger } from '@/lib/logs/console/logger' import { StorageService } from '@/lib/uploads' @@ -147,6 +148,10 @@ export async function POST(request: NextRequest) { { status: 400 } ) } + const voiceIdValidation = validateAlphanumericId(body.voiceId, 'voiceId') + if (!voiceIdValidation.isValid) { + return NextResponse.json({ error: voiceIdValidation.error }, { status: 400 }) + } const result = await synthesizeWithElevenLabs({ text, apiKey, diff --git a/apps/sim/app/api/tools/discord/send-message/route.ts b/apps/sim/app/api/tools/discord/send-message/route.ts index 205149a7df..ef6df171dc 100644 --- a/apps/sim/app/api/tools/discord/send-message/route.ts +++ b/apps/sim/app/api/tools/discord/send-message/route.ts @@ -1,6 +1,7 @@ import { type NextRequest, NextResponse } from 'next/server' import { z } from 'zod' import { checkHybridAuth } from '@/lib/auth/hybrid' +import { validateNumericId } from '@/lib/core/security/input-validation' import { generateRequestId } from '@/lib/core/utils/request' import { createLogger } from '@/lib/logs/console/logger' import { processFilesToUserFiles } from '@/lib/uploads/utils/file-utils' @@ -41,6 +42,17 @@ export async function POST(request: NextRequest) { const body = await request.json() const validatedData = DiscordSendMessageSchema.parse(body) + const channelIdValidation = validateNumericId(validatedData.channelId, 'channelId') + if (!channelIdValidation.isValid) { + logger.warn(`[${requestId}] Invalid channelId format`, { + error: channelIdValidation.error, + }) + return NextResponse.json( + { success: false, error: channelIdValidation.error }, + { status: 400 } + ) + } + logger.info(`[${requestId}] Sending Discord message`, { channelId: validatedData.channelId, hasFiles: !!(validatedData.files && validatedData.files.length > 0), diff --git a/apps/sim/app/api/tools/webflow/collections/route.ts b/apps/sim/app/api/tools/webflow/collections/route.ts index 2aa17de0da..31ec540615 100644 --- a/apps/sim/app/api/tools/webflow/collections/route.ts +++ b/apps/sim/app/api/tools/webflow/collections/route.ts @@ -1,5 +1,6 @@ import { NextResponse } from 'next/server' import { authorizeCredentialUse } from '@/lib/auth/credential-access' +import { validateAlphanumericId } from '@/lib/core/security/input-validation' import { generateRequestId } from '@/lib/core/utils/request' import { createLogger } from '@/lib/logs/console/logger' import { refreshAccessTokenIfNeeded } from '@/app/api/auth/oauth/utils' @@ -19,9 +20,10 @@ export async function POST(request: Request) { return NextResponse.json({ error: 'Credential is required' }, { status: 400 }) } - if (!siteId) { - logger.error('Missing siteId in request') - return NextResponse.json({ error: 'Site ID is required' }, { status: 400 }) + const siteIdValidation = validateAlphanumericId(siteId, 'siteId') + if (!siteIdValidation.isValid) { + logger.error('Invalid siteId', { error: siteIdValidation.error }) + return NextResponse.json({ error: siteIdValidation.error }, { status: 400 }) } const authz = await authorizeCredentialUse(request as any, { diff --git a/apps/sim/app/api/tools/webflow/items/route.ts b/apps/sim/app/api/tools/webflow/items/route.ts index 8639c63e35..95acc644d7 100644 --- a/apps/sim/app/api/tools/webflow/items/route.ts +++ b/apps/sim/app/api/tools/webflow/items/route.ts @@ -1,5 +1,6 @@ import { NextResponse } from 'next/server' import { authorizeCredentialUse } from '@/lib/auth/credential-access' +import { validateAlphanumericId } from '@/lib/core/security/input-validation' import { generateRequestId } from '@/lib/core/utils/request' import { createLogger } from '@/lib/logs/console/logger' import { refreshAccessTokenIfNeeded } from '@/app/api/auth/oauth/utils' @@ -19,9 +20,10 @@ export async function POST(request: Request) { return NextResponse.json({ error: 'Credential is required' }, { status: 400 }) } - if (!collectionId) { - logger.error('Missing collectionId in request') - return NextResponse.json({ error: 'Collection ID is required' }, { status: 400 }) + const collectionIdValidation = validateAlphanumericId(collectionId, 'collectionId') + if (!collectionIdValidation.isValid) { + logger.error('Invalid collectionId', { error: collectionIdValidation.error }) + return NextResponse.json({ error: collectionIdValidation.error }, { status: 400 }) } const authz = await authorizeCredentialUse(request as any, {