Skip to content

Commit f32b53b

Browse files
waleedlatif1claude
andcommitted
fix(hubspot): validate credentialId in selector routes
Mirrors the Gmail/Webflow/Jira selector route security pattern by rejecting non-alphanumeric credentialId values before authorization or token refresh. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
1 parent 84fe0e4 commit f32b53b

4 files changed

Lines changed: 28 additions & 0 deletions

File tree

apps/sim/app/api/tools/hubspot/lists/route.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { type NextRequest, NextResponse } from 'next/server'
33
import { hubspotListsSelectorContract } from '@/lib/api/contracts/selectors/hubspot'
44
import { parseRequest } from '@/lib/api/server'
55
import { authorizeCredentialUse } from '@/lib/auth/credential-access'
6+
import { validateAlphanumericId } from '@/lib/core/security/input-validation'
67
import { generateRequestId } from '@/lib/core/utils/request'
78
import { withRouteHandler } from '@/lib/core/utils/with-route-handler'
89
import { refreshAccessTokenIfNeeded } from '@/app/api/auth/oauth/utils'
@@ -27,6 +28,12 @@ export const GET = withRouteHandler(async (request: NextRequest) => {
2728
if (!parsed.success) return parsed.response
2829
const { credentialId, objectTypeId, query } = parsed.data.query
2930

31+
const credentialIdValidation = validateAlphanumericId(credentialId, 'credentialId', 255)
32+
if (!credentialIdValidation.isValid) {
33+
logger.warn(`[${requestId}] Invalid credential ID: ${credentialIdValidation.error}`)
34+
return NextResponse.json({ error: credentialIdValidation.error }, { status: 400 })
35+
}
36+
3037
const authz = await authorizeCredentialUse(request, {
3138
credentialId,
3239
requireWorkflowIdForInternal: false,

apps/sim/app/api/tools/hubspot/owners/route.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { type NextRequest, NextResponse } from 'next/server'
33
import { hubspotOwnersSelectorContract } from '@/lib/api/contracts/selectors/hubspot'
44
import { parseRequest } from '@/lib/api/server'
55
import { authorizeCredentialUse } from '@/lib/auth/credential-access'
6+
import { validateAlphanumericId } from '@/lib/core/security/input-validation'
67
import { generateRequestId } from '@/lib/core/utils/request'
78
import { withRouteHandler } from '@/lib/core/utils/with-route-handler'
89
import { refreshAccessTokenIfNeeded } from '@/app/api/auth/oauth/utils'
@@ -27,6 +28,12 @@ export const GET = withRouteHandler(async (request: NextRequest) => {
2728
if (!parsed.success) return parsed.response
2829
const { credentialId, query } = parsed.data.query
2930

31+
const credentialIdValidation = validateAlphanumericId(credentialId, 'credentialId', 255)
32+
if (!credentialIdValidation.isValid) {
33+
logger.warn(`[${requestId}] Invalid credential ID: ${credentialIdValidation.error}`)
34+
return NextResponse.json({ error: credentialIdValidation.error }, { status: 400 })
35+
}
36+
3037
const authz = await authorizeCredentialUse(request, {
3138
credentialId,
3239
requireWorkflowIdForInternal: false,

apps/sim/app/api/tools/hubspot/pipelines/route.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { type NextRequest, NextResponse } from 'next/server'
33
import { hubspotPipelinesSelectorContract } from '@/lib/api/contracts/selectors/hubspot'
44
import { parseRequest } from '@/lib/api/server'
55
import { authorizeCredentialUse } from '@/lib/auth/credential-access'
6+
import { validateAlphanumericId } from '@/lib/core/security/input-validation'
67
import { generateRequestId } from '@/lib/core/utils/request'
78
import { withRouteHandler } from '@/lib/core/utils/with-route-handler'
89
import { refreshAccessTokenIfNeeded } from '@/app/api/auth/oauth/utils'
@@ -33,6 +34,12 @@ export const GET = withRouteHandler(async (request: NextRequest) => {
3334
if (!parsed.success) return parsed.response
3435
const { credentialId, objectType } = parsed.data.query
3536

37+
const credentialIdValidation = validateAlphanumericId(credentialId, 'credentialId', 255)
38+
if (!credentialIdValidation.isValid) {
39+
logger.warn(`[${requestId}] Invalid credential ID: ${credentialIdValidation.error}`)
40+
return NextResponse.json({ error: credentialIdValidation.error }, { status: 400 })
41+
}
42+
3643
const authz = await authorizeCredentialUse(request, {
3744
credentialId,
3845
requireWorkflowIdForInternal: false,

apps/sim/app/api/tools/hubspot/properties/route.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { type NextRequest, NextResponse } from 'next/server'
33
import { hubspotPropertiesSelectorContract } from '@/lib/api/contracts/selectors/hubspot'
44
import { parseRequest } from '@/lib/api/server'
55
import { authorizeCredentialUse } from '@/lib/auth/credential-access'
6+
import { validateAlphanumericId } from '@/lib/core/security/input-validation'
67
import { generateRequestId } from '@/lib/core/utils/request'
78
import { withRouteHandler } from '@/lib/core/utils/with-route-handler'
89
import { refreshAccessTokenIfNeeded } from '@/app/api/auth/oauth/utils'
@@ -36,6 +37,12 @@ export const GET = withRouteHandler(async (request: NextRequest) => {
3637
if (!parsed.success) return parsed.response
3738
const { credentialId, objectType, query } = parsed.data.query
3839

40+
const credentialIdValidation = validateAlphanumericId(credentialId, 'credentialId', 255)
41+
if (!credentialIdValidation.isValid) {
42+
logger.warn(`[${requestId}] Invalid credential ID: ${credentialIdValidation.error}`)
43+
return NextResponse.json({ error: credentialIdValidation.error }, { status: 400 })
44+
}
45+
3946
const authz = await authorizeCredentialUse(request, {
4047
credentialId,
4148
requireWorkflowIdForInternal: false,

0 commit comments

Comments
 (0)