@@ -18,13 +18,11 @@ export async function createMySQLConnection(config: MySQLConnectionConfig) {
1818 password : config . password ,
1919 }
2020
21- // Handle SSL configuration
2221 if ( config . ssl === 'required' ) {
2322 connectionConfig . ssl = { rejectUnauthorized : true }
2423 } else if ( config . ssl === 'preferred' ) {
2524 connectionConfig . ssl = { rejectUnauthorized : false }
2625 }
27- // For 'disabled', we don't set the ssl property at all
2826
2927 return mysql . createConnection ( connectionConfig )
3028}
@@ -54,7 +52,6 @@ export async function executeQuery(
5452export function validateQuery ( query : string ) : { isValid : boolean ; error ?: string } {
5553 const trimmedQuery = query . trim ( ) . toLowerCase ( )
5654
57- // Block dangerous SQL operations
5855 const dangerousPatterns = [
5956 / d r o p \s + d a t a b a s e / i,
6057 / d r o p \s + s c h e m a / i,
@@ -91,7 +88,6 @@ export function validateQuery(query: string): { isValid: boolean; error?: string
9188 }
9289 }
9390
94- // Only allow specific statement types for execute endpoint
9591 const allowedStatements = / ^ ( s e l e c t | i n s e r t | u p d a t e | d e l e t e | w i t h | s h o w | d e s c r i b e | e x p l a i n ) \s + / i
9692 if ( ! allowedStatements . test ( trimmedQuery ) ) {
9793 return {
@@ -116,6 +112,8 @@ export function buildInsertQuery(table: string, data: Record<string, unknown>) {
116112}
117113
118114export function buildUpdateQuery ( table : string , data : Record < string , unknown > , where : string ) {
115+ validateWhereClause ( where )
116+
119117 const sanitizedTable = sanitizeIdentifier ( table )
120118 const columns = Object . keys ( data )
121119 const values = Object . values ( data )
@@ -127,14 +125,33 @@ export function buildUpdateQuery(table: string, data: Record<string, unknown>, w
127125}
128126
129127export function buildDeleteQuery ( table : string , where : string ) {
128+ validateWhereClause ( where )
129+
130130 const sanitizedTable = sanitizeIdentifier ( table )
131131 const query = `DELETE FROM ${ sanitizedTable } WHERE ${ where } `
132132
133133 return { query, values : [ ] }
134134}
135135
136+ function validateWhereClause ( where : string ) : void {
137+ const dangerousPatterns = [
138+ / ; \s * ( d r o p | d e l e t e | i n s e r t | u p d a t e | c r e a t e | a l t e r | g r a n t | r e v o k e ) / i,
139+ / u n i o n \s + s e l e c t / i,
140+ / i n t o \s + o u t f i l e / i,
141+ / l o a d _ f i l e / i,
142+ / - - / ,
143+ / \/ \* / ,
144+ / \* \/ / ,
145+ ]
146+
147+ for ( const pattern of dangerousPatterns ) {
148+ if ( pattern . test ( where ) ) {
149+ throw new Error ( 'WHERE clause contains potentially dangerous operation' )
150+ }
151+ }
152+ }
153+
136154export function sanitizeIdentifier ( identifier : string ) : string {
137- // Handle schema.table format
138155 if ( identifier . includes ( '.' ) ) {
139156 const parts = identifier . split ( '.' )
140157 return parts . map ( ( part ) => sanitizeSingleIdentifier ( part ) ) . join ( '.' )
@@ -144,16 +161,13 @@ export function sanitizeIdentifier(identifier: string): string {
144161}
145162
146163function sanitizeSingleIdentifier ( identifier : string ) : string {
147- // Remove any existing backticks to prevent double-escaping
148164 const cleaned = identifier . replace ( / ` / g, '' )
149165
150- // Validate identifier contains only safe characters
151166 if ( ! / ^ [ a - z A - Z _ ] [ a - z A - Z 0 - 9 _ ] * $ / . test ( cleaned ) ) {
152167 throw new Error (
153168 `Invalid identifier: ${ identifier } . Identifiers must start with a letter or underscore and contain only letters, numbers, and underscores.`
154169 )
155170 }
156171
157- // Wrap in backticks for MySQL
158172 return `\`${ cleaned } \``
159173}
0 commit comments