Skip to content

Commit 12231db

Browse files
waleedlatif1claude
andcommitted
fix(microsoft-excel): use validatePathSegment with strict pattern for driveId/spreadsheetId
Replace validateMicrosoftGraphId with validatePathSegment using a custom pattern ^[a-zA-Z0-9!_-]+$ for all URL-interpolated IDs. validatePathSegment blocks /, \, path traversal, and null bytes before checking the pattern, preventing URL-modifying characters like ?, #, & from altering the Graph API endpoint. The pattern allows ! for SharePoint b!<base64> drive IDs. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 3be18ca commit 12231db

4 files changed

Lines changed: 33 additions & 10 deletions

File tree

apps/sim/app/api/auth/oauth/microsoft/files/route.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { createLogger } from '@sim/logger'
22
import { type NextRequest, NextResponse } from 'next/server'
33
import { authorizeCredentialUse } from '@/lib/auth/credential-access'
4-
import { validateMicrosoftGraphId } from '@/lib/core/security/input-validation'
4+
import { validatePathSegment } from '@/lib/core/security/input-validation'
55
import { generateRequestId } from '@/lib/core/utils/request'
66
import { getCredential, refreshAccessTokenIfNeeded } from '@/app/api/auth/oauth/utils'
77

@@ -77,7 +77,10 @@ export async function GET(request: NextRequest) {
7777
// When driveId is provided (SharePoint), search within that specific drive.
7878
// Otherwise, search the user's personal OneDrive.
7979
if (driveId) {
80-
const driveIdValidation = validateMicrosoftGraphId(driveId, 'driveId')
80+
const driveIdValidation = validatePathSegment(driveId, {
81+
paramName: 'driveId',
82+
customPattern: /^[a-zA-Z0-9!_-]+$/,
83+
})
8184
if (!driveIdValidation.isValid) {
8285
return NextResponse.json({ error: driveIdValidation.error }, { status: 400 })
8386
}

apps/sim/app/api/tools/microsoft_excel/drives/route.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { createLogger } from '@sim/logger'
22
import { type NextRequest, NextResponse } from 'next/server'
33
import { authorizeCredentialUse } from '@/lib/auth/credential-access'
44
import {
5-
validateMicrosoftGraphId,
5+
validatePathSegment,
66
validateSharePointSiteId,
77
} from '@/lib/core/security/input-validation'
88
import { generateRequestId } from '@/lib/core/utils/request'
@@ -70,7 +70,10 @@ export async function POST(request: NextRequest) {
7070

7171
// Single-drive lookup when driveId is provided (used by fetchById)
7272
if (driveId) {
73-
const driveIdValidation = validateMicrosoftGraphId(driveId, 'driveId')
73+
const driveIdValidation = validatePathSegment(driveId, {
74+
paramName: 'driveId',
75+
customPattern: /^[a-zA-Z0-9!_-]+$/,
76+
})
7477
if (!driveIdValidation.isValid) {
7578
return NextResponse.json({ error: driveIdValidation.error }, { status: 400 })
7679
}

apps/sim/app/api/tools/microsoft_excel/sheets/route.ts

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { createLogger } from '@sim/logger'
22
import { type NextRequest, NextResponse } from 'next/server'
33
import { authorizeCredentialUse } from '@/lib/auth/credential-access'
4-
import { validateMicrosoftGraphId } from '@/lib/core/security/input-validation'
4+
import { validatePathSegment } from '@/lib/core/security/input-validation'
55
import { generateRequestId } from '@/lib/core/utils/request'
66
import { refreshAccessTokenIfNeeded } from '@/app/api/auth/oauth/utils'
77

@@ -63,13 +63,21 @@ export async function GET(request: NextRequest) {
6363
`[${requestId}] Fetching worksheets from Microsoft Graph API for workbook ${spreadsheetId}`
6464
)
6565

66-
const spreadsheetValidation = validateMicrosoftGraphId(spreadsheetId, 'spreadsheetId')
66+
const graphIdPattern = /^[a-zA-Z0-9!_-]+$/
67+
68+
const spreadsheetValidation = validatePathSegment(spreadsheetId, {
69+
paramName: 'spreadsheetId',
70+
customPattern: graphIdPattern,
71+
})
6772
if (!spreadsheetValidation.isValid) {
6873
return NextResponse.json({ error: spreadsheetValidation.error }, { status: 400 })
6974
}
7075

7176
if (driveId) {
72-
const driveIdValidation = validateMicrosoftGraphId(driveId, 'driveId')
77+
const driveIdValidation = validatePathSegment(driveId, {
78+
paramName: 'driveId',
79+
customPattern: graphIdPattern,
80+
})
7381
if (!driveIdValidation.isValid) {
7482
return NextResponse.json({ error: driveIdValidation.error }, { status: 400 })
7583
}

apps/sim/tools/microsoft_excel/utils.ts

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { createLogger } from '@sim/logger'
2-
import { validateMicrosoftGraphId } from '@/lib/core/security/input-validation'
2+
import { validatePathSegment } from '@/lib/core/security/input-validation'
33
import type { ExcelCellValue } from '@/tools/microsoft_excel/types'
44

55
const logger = createLogger('MicrosoftExcelUtils')
@@ -9,14 +9,23 @@ const logger = createLogger('MicrosoftExcelUtils')
99
* When driveId is provided, uses /drives/{driveId}/items/{itemId} (SharePoint/shared drives).
1010
* When driveId is omitted, uses /me/drive/items/{itemId} (personal OneDrive).
1111
*/
12+
/** Pattern for Microsoft Graph item/drive IDs: alphanumeric, hyphens, underscores, and ! (for SharePoint b!<base64> format) */
13+
const GRAPH_ID_PATTERN = /^[a-zA-Z0-9!_-]+$/
14+
1215
export function getItemBasePath(spreadsheetId: string, driveId?: string): string {
13-
const spreadsheetValidation = validateMicrosoftGraphId(spreadsheetId, 'spreadsheetId')
16+
const spreadsheetValidation = validatePathSegment(spreadsheetId, {
17+
paramName: 'spreadsheetId',
18+
customPattern: GRAPH_ID_PATTERN,
19+
})
1420
if (!spreadsheetValidation.isValid) {
1521
throw new Error(spreadsheetValidation.error)
1622
}
1723

1824
if (driveId) {
19-
const driveValidation = validateMicrosoftGraphId(driveId, 'driveId')
25+
const driveValidation = validatePathSegment(driveId, {
26+
paramName: 'driveId',
27+
customPattern: GRAPH_ID_PATTERN,
28+
})
2029
if (!driveValidation.isValid) {
2130
throw new Error(driveValidation.error)
2231
}

0 commit comments

Comments
 (0)