Skip to content

Commit 883c701

Browse files
author
aadamgough
committed
fixed vulnerability and lint
1 parent f093f97 commit 883c701

4 files changed

Lines changed: 66 additions & 14 deletions

File tree

apps/sim/tools/snowflake/delete_rows.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import type {
33
SnowflakeDeleteRowsParams,
44
SnowflakeDeleteRowsResponse,
55
} from '@/tools/snowflake/types'
6-
import { parseAccountUrl } from '@/tools/snowflake/utils'
6+
import { parseAccountUrl, sanitizeIdentifier, validateWhereClause } from '@/tools/snowflake/utils'
77
import type { ToolConfig } from '@/tools/types'
88

99
const logger = createLogger('SnowflakeDeleteRowsTool')
@@ -17,12 +17,15 @@ function buildDeleteSQL(
1717
table: string,
1818
whereClause?: string
1919
): string {
20-
const fullTableName = `${database}.${schema}.${table}`
20+
const sanitizedDatabase = sanitizeIdentifier(database)
21+
const sanitizedSchema = sanitizeIdentifier(schema)
22+
const sanitizedTable = sanitizeIdentifier(table)
23+
const fullTableName = `${sanitizedDatabase}.${sanitizedSchema}.${sanitizedTable}`
2124

2225
let sql = `DELETE FROM ${fullTableName}`
2326

24-
// Add WHERE clause if provided
2527
if (whereClause?.trim()) {
28+
validateWhereClause(whereClause)
2629
sql += ` WHERE ${whereClause}`
2730
}
2831

apps/sim/tools/snowflake/insert_rows.ts

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,13 @@ import type {
33
SnowflakeInsertRowsParams,
44
SnowflakeInsertRowsResponse,
55
} from '@/tools/snowflake/types'
6-
import { parseAccountUrl } from '@/tools/snowflake/utils'
6+
import { parseAccountUrl, sanitizeIdentifier } from '@/tools/snowflake/utils'
77
import type { ToolConfig } from '@/tools/types'
88

99
const logger = createLogger('SnowflakeInsertRowsTool')
1010

1111
/**
12-
* Build INSERT SQL statement from parameters
12+
* Build INSERT SQL statement from parameters with proper identifier quoting
1313
*/
1414
function buildInsertSQL(
1515
database: string,
@@ -18,10 +18,13 @@ function buildInsertSQL(
1818
columns: string[],
1919
values: any[][]
2020
): string {
21-
const fullTableName = `${database}.${schema}.${table}`
22-
const columnList = columns.join(', ')
21+
const sanitizedDatabase = sanitizeIdentifier(database)
22+
const sanitizedSchema = sanitizeIdentifier(schema)
23+
const sanitizedTable = sanitizeIdentifier(table)
24+
const fullTableName = `${sanitizedDatabase}.${sanitizedSchema}.${sanitizedTable}`
25+
26+
const columnList = columns.map((col) => sanitizeIdentifier(col)).join(', ')
2327

24-
// Build values clause for multiple rows
2528
const valuesClause = values
2629
.map((rowValues) => {
2730
const formattedValues = rowValues.map((val) => {

apps/sim/tools/snowflake/update_rows.ts

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,13 @@ import type {
33
SnowflakeUpdateRowsParams,
44
SnowflakeUpdateRowsResponse,
55
} from '@/tools/snowflake/types'
6-
import { parseAccountUrl } from '@/tools/snowflake/utils'
6+
import { parseAccountUrl, sanitizeIdentifier, validateWhereClause } from '@/tools/snowflake/utils'
77
import type { ToolConfig } from '@/tools/types'
88

99
const logger = createLogger('SnowflakeUpdateRowsTool')
1010

1111
/**
12-
* Build UPDATE SQL statement from parameters
12+
* Build UPDATE SQL statement from parameters with proper identifier quoting
1313
*/
1414
function buildUpdateSQL(
1515
database: string,
@@ -18,11 +18,15 @@ function buildUpdateSQL(
1818
updates: Record<string, any>,
1919
whereClause?: string
2020
): string {
21-
const fullTableName = `${database}.${schema}.${table}`
21+
const sanitizedDatabase = sanitizeIdentifier(database)
22+
const sanitizedSchema = sanitizeIdentifier(schema)
23+
const sanitizedTable = sanitizeIdentifier(table)
24+
const fullTableName = `${sanitizedDatabase}.${sanitizedSchema}.${sanitizedTable}`
2225

23-
// Build SET clause
2426
const setClause = Object.entries(updates)
2527
.map(([column, value]) => {
28+
const sanitizedColumn = sanitizeIdentifier(column)
29+
2630
let formattedValue: string
2731

2832
if (value === null || value === undefined) {
@@ -36,14 +40,14 @@ function buildUpdateSQL(
3640
formattedValue = String(value)
3741
}
3842

39-
return `${column} = ${formattedValue}`
43+
return `${sanitizedColumn} = ${formattedValue}`
4044
})
4145
.join(', ')
4246

4347
let sql = `UPDATE ${fullTableName} SET ${setClause}`
4448

45-
// Add WHERE clause if provided
4649
if (whereClause?.trim()) {
50+
validateWhereClause(whereClause)
4751
sql += ` WHERE ${whereClause}`
4852
}
4953

apps/sim/tools/snowflake/utils.ts

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,3 +140,45 @@ export function extractColumnMetadata(response: any): Array<{ name: string; type
140140
type: col.type,
141141
}))
142142
}
143+
144+
export function sanitizeIdentifier(identifier: string): string {
145+
if (identifier.includes('.')) {
146+
const parts = identifier.split('.')
147+
return parts.map((part) => sanitizeSingleIdentifier(part)).join('.')
148+
}
149+
150+
return sanitizeSingleIdentifier(identifier)
151+
}
152+
153+
export function validateWhereClause(where: string): void {
154+
const dangerousPatterns = [
155+
/;\s*(drop|delete|insert|update|create|alter|grant|revoke|truncate)/i,
156+
/union\s+select/i,
157+
/into\s+outfile/i,
158+
/load_file/i,
159+
/--/,
160+
/\/\*/,
161+
/\*\//,
162+
/xp_cmdshell/i,
163+
/exec\s*\(/i,
164+
/execute\s+immediate/i,
165+
]
166+
167+
for (const pattern of dangerousPatterns) {
168+
if (pattern.test(where)) {
169+
throw new Error('WHERE clause contains potentially dangerous operation')
170+
}
171+
}
172+
}
173+
174+
function sanitizeSingleIdentifier(identifier: string): string {
175+
const cleaned = identifier.replace(/"/g, '')
176+
177+
if (!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(cleaned)) {
178+
throw new Error(
179+
`Invalid identifier: ${identifier}. Identifiers must start with a letter or underscore and contain only letters, numbers, and underscores.`
180+
)
181+
}
182+
183+
return `"${cleaned}"`
184+
}

0 commit comments

Comments
 (0)