fixed vulnerability and lint

This commit is contained in:
aadamgough
2025-11-29 14:27:49 -08:00
parent f093f97cc8
commit 883c70140a
4 changed files with 66 additions and 14 deletions

View File

@@ -3,7 +3,7 @@ import type {
SnowflakeDeleteRowsParams,
SnowflakeDeleteRowsResponse,
} from '@/tools/snowflake/types'
import { parseAccountUrl } from '@/tools/snowflake/utils'
import { parseAccountUrl, sanitizeIdentifier, validateWhereClause } from '@/tools/snowflake/utils'
import type { ToolConfig } from '@/tools/types'
const logger = createLogger('SnowflakeDeleteRowsTool')
@@ -17,12 +17,15 @@ function buildDeleteSQL(
table: string,
whereClause?: string
): string {
const fullTableName = `${database}.${schema}.${table}`
const sanitizedDatabase = sanitizeIdentifier(database)
const sanitizedSchema = sanitizeIdentifier(schema)
const sanitizedTable = sanitizeIdentifier(table)
const fullTableName = `${sanitizedDatabase}.${sanitizedSchema}.${sanitizedTable}`
let sql = `DELETE FROM ${fullTableName}`
// Add WHERE clause if provided
if (whereClause?.trim()) {
validateWhereClause(whereClause)
sql += ` WHERE ${whereClause}`
}

View File

@@ -3,13 +3,13 @@ import type {
SnowflakeInsertRowsParams,
SnowflakeInsertRowsResponse,
} from '@/tools/snowflake/types'
import { parseAccountUrl } from '@/tools/snowflake/utils'
import { parseAccountUrl, sanitizeIdentifier } from '@/tools/snowflake/utils'
import type { ToolConfig } from '@/tools/types'
const logger = createLogger('SnowflakeInsertRowsTool')
/**
* Build INSERT SQL statement from parameters
* Build INSERT SQL statement from parameters with proper identifier quoting
*/
function buildInsertSQL(
database: string,
@@ -18,10 +18,13 @@ function buildInsertSQL(
columns: string[],
values: any[][]
): string {
const fullTableName = `${database}.${schema}.${table}`
const columnList = columns.join(', ')
const sanitizedDatabase = sanitizeIdentifier(database)
const sanitizedSchema = sanitizeIdentifier(schema)
const sanitizedTable = sanitizeIdentifier(table)
const fullTableName = `${sanitizedDatabase}.${sanitizedSchema}.${sanitizedTable}`
const columnList = columns.map((col) => sanitizeIdentifier(col)).join(', ')
// Build values clause for multiple rows
const valuesClause = values
.map((rowValues) => {
const formattedValues = rowValues.map((val) => {

View File

@@ -3,13 +3,13 @@ import type {
SnowflakeUpdateRowsParams,
SnowflakeUpdateRowsResponse,
} from '@/tools/snowflake/types'
import { parseAccountUrl } from '@/tools/snowflake/utils'
import { parseAccountUrl, sanitizeIdentifier, validateWhereClause } from '@/tools/snowflake/utils'
import type { ToolConfig } from '@/tools/types'
const logger = createLogger('SnowflakeUpdateRowsTool')
/**
* Build UPDATE SQL statement from parameters
* Build UPDATE SQL statement from parameters with proper identifier quoting
*/
function buildUpdateSQL(
database: string,
@@ -18,11 +18,15 @@ function buildUpdateSQL(
updates: Record<string, any>,
whereClause?: string
): string {
const fullTableName = `${database}.${schema}.${table}`
const sanitizedDatabase = sanitizeIdentifier(database)
const sanitizedSchema = sanitizeIdentifier(schema)
const sanitizedTable = sanitizeIdentifier(table)
const fullTableName = `${sanitizedDatabase}.${sanitizedSchema}.${sanitizedTable}`
// Build SET clause
const setClause = Object.entries(updates)
.map(([column, value]) => {
const sanitizedColumn = sanitizeIdentifier(column)
let formattedValue: string
if (value === null || value === undefined) {
@@ -36,14 +40,14 @@ function buildUpdateSQL(
formattedValue = String(value)
}
return `${column} = ${formattedValue}`
return `${sanitizedColumn} = ${formattedValue}`
})
.join(', ')
let sql = `UPDATE ${fullTableName} SET ${setClause}`
// Add WHERE clause if provided
if (whereClause?.trim()) {
validateWhereClause(whereClause)
sql += ` WHERE ${whereClause}`
}

View File

@@ -140,3 +140,45 @@ export function extractColumnMetadata(response: any): Array<{ name: string; type
type: col.type,
}))
}
export function sanitizeIdentifier(identifier: string): string {
if (identifier.includes('.')) {
const parts = identifier.split('.')
return parts.map((part) => sanitizeSingleIdentifier(part)).join('.')
}
return sanitizeSingleIdentifier(identifier)
}
export function validateWhereClause(where: string): void {
const dangerousPatterns = [
/;\s*(drop|delete|insert|update|create|alter|grant|revoke|truncate)/i,
/union\s+select/i,
/into\s+outfile/i,
/load_file/i,
/--/,
/\/\*/,
/\*\//,
/xp_cmdshell/i,
/exec\s*\(/i,
/execute\s+immediate/i,
]
for (const pattern of dangerousPatterns) {
if (pattern.test(where)) {
throw new Error('WHERE clause contains potentially dangerous operation')
}
}
}
function sanitizeSingleIdentifier(identifier: string): string {
const cleaned = identifier.replace(/"/g, '')
if (!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(cleaned)) {
throw new Error(
`Invalid identifier: ${identifier}. Identifiers must start with a letter or underscore and contain only letters, numbers, and underscores.`
)
}
return `"${cleaned}"`
}