@memberjunction/global 5.1.0 → 5.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +19 -3
- package/dist/SQLExpressionValidator.d.ts +31 -4
- package/dist/SQLExpressionValidator.d.ts.map +1 -1
- package/dist/SQLExpressionValidator.js +107 -22
- package/dist/SQLExpressionValidator.js.map +1 -1
- package/dist/__tests__/SQLExpressionValidator.security.test.d.ts +2 -0
- package/dist/__tests__/SQLExpressionValidator.security.test.d.ts.map +1 -0
- package/dist/__tests__/SQLExpressionValidator.security.test.js +328 -0
- package/dist/__tests__/SQLExpressionValidator.security.test.js.map +1 -0
- package/dist/__tests__/SQLExpressionValidator.test.d.ts +2 -0
- package/dist/__tests__/SQLExpressionValidator.test.d.ts.map +1 -0
- package/dist/__tests__/SQLExpressionValidator.test.js +350 -0
- package/dist/__tests__/SQLExpressionValidator.test.js.map +1 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -324,7 +324,9 @@ Supports comparisons (`==`, `!=`, `<`, `>`, `<=`, `>=`), logical operators (`&&`
|
|
|
324
324
|
|
|
325
325
|
### SQLExpressionValidator
|
|
326
326
|
|
|
327
|
-
Validates user-provided SQL expressions against injection attacks. Provides context-aware validation (WHERE clauses, ORDER BY, aggregates, field references) with an allowlist of safe SQL functions.
|
|
327
|
+
Validates user-provided SQL expressions and full queries against injection attacks. Provides context-aware validation (WHERE clauses, ORDER BY, aggregates, field references, full queries) with an allowlist of safe SQL functions.
|
|
328
|
+
|
|
329
|
+
**Expression validation** (WHERE clauses, aggregates, ORDER BY):
|
|
328
330
|
|
|
329
331
|
```typescript
|
|
330
332
|
import { SQLExpressionValidator } from '@memberjunction/global';
|
|
@@ -342,9 +344,22 @@ const bad = validator.validate("Name = 'test'; 1=1", {
|
|
|
342
344
|
context: 'where_clause'
|
|
343
345
|
});
|
|
344
346
|
// bad.valid === false
|
|
345
|
-
// bad.error === "Semicolons are not allowed in SQL expressions"
|
|
346
347
|
```
|
|
347
348
|
|
|
349
|
+
**Full query validation** (ad-hoc SELECT/WITH statements):
|
|
350
|
+
|
|
351
|
+
```typescript
|
|
352
|
+
// Validate a complete SQL query — allows SELECT, JOINs, subqueries, set operations, comments
|
|
353
|
+
const result = validator.validateFullQuery('SELECT TOP 10 * FROM __mj.vwUsers WHERE IsActive = 1');
|
|
354
|
+
// result.valid === true
|
|
355
|
+
|
|
356
|
+
// Mutations and dangerous operations are blocked
|
|
357
|
+
const bad = validator.validateFullQuery("INSERT INTO Users (Name) VALUES ('hacked')");
|
|
358
|
+
// bad.valid === false, bad.trigger === 'INSERT'
|
|
359
|
+
```
|
|
360
|
+
|
|
361
|
+
The `full_query` context allows keywords that are legitimate in SELECT statements (EXISTS, ANY, ALL, UNION, INTERSECT, EXCEPT, IF) while still blocking all mutations (INSERT, UPDATE, DELETE, DROP, etc.), dangerous operations (EXEC, OPENROWSET, WAITFOR), and multi-statement injection (semicolons).
|
|
362
|
+
|
|
348
363
|
### ClassUtils -- Reflection Helpers
|
|
349
364
|
|
|
350
365
|
Functions for introspecting class hierarchies at runtime.
|
|
@@ -589,7 +604,8 @@ function RegisterClass(
|
|
|
589
604
|
| Method | Returns | Description |
|
|
590
605
|
|---|---|---|
|
|
591
606
|
| `Instance` (static) | `SQLExpressionValidator` | Singleton accessor |
|
|
592
|
-
| `validate(expression, options)` | `SQLValidationResult` | Validate a SQL expression |
|
|
607
|
+
| `validate(expression, options)` | `SQLValidationResult` | Validate a SQL expression with context-specific rules |
|
|
608
|
+
| `validateFullQuery(sql)` | `SQLValidationResult` | Validate a full SELECT/WITH query (convenience for `validate(sql, { context: 'full_query' })`) |
|
|
593
609
|
|
|
594
610
|
### WarningManager
|
|
595
611
|
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @fileoverview Unified SQL Expression Validation
|
|
2
|
+
* @fileoverview Unified SQL Expression and Query Validation
|
|
3
3
|
*
|
|
4
|
-
* Central utility for validating user-provided SQL expressions
|
|
5
|
-
* Used by RunView, aggregates, smart filters,
|
|
4
|
+
* Central utility for validating user-provided SQL expressions and full queries
|
|
5
|
+
* against injection attacks. Used by RunView, aggregates, smart filters, ad-hoc
|
|
6
|
+
* query execution, and any other feature accepting SQL input.
|
|
6
7
|
*
|
|
7
8
|
* Located in MJGlobal (lowest-level package) so all packages can use it.
|
|
8
9
|
*
|
|
@@ -12,6 +13,11 @@
|
|
|
12
13
|
* Dangerous SQL keywords that are never allowed in user-provided expressions
|
|
13
14
|
*/
|
|
14
15
|
export declare const DANGEROUS_SQL_KEYWORDS: readonly ["DROP", "CREATE", "ALTER", "TRUNCATE", "RENAME", "INSERT", "UPDATE", "DELETE", "MERGE", "REPLACE", "GRANT", "REVOKE", "DENY", "EXEC", "EXECUTE", "CALL", "PROCEDURE", "FUNCTION", "BEGIN", "COMMIT", "ROLLBACK", "SAVEPOINT", "USE", "DATABASE", "SCHEMA", "IF", "WHILE", "LOOP", "FOR", "GOTO", "UNION", "INTERSECT", "EXCEPT", "EXISTS", "ANY", "ALL", "SOME", "BULK", "OPENROWSET", "OPENDATASOURCE", "OPENQUERY", "XP_", "SP_", "DYNAMIC", "PREPARE", "DEALLOCATE", "WAITFOR", "DELAY", "SLEEP", "SHUTDOWN", "RECONFIGURE"];
|
|
16
|
+
/**
|
|
17
|
+
* Keywords from DANGEROUS_SQL_KEYWORDS that are legitimate in full SELECT queries.
|
|
18
|
+
* These are only unblocked when context is 'full_query'.
|
|
19
|
+
*/
|
|
20
|
+
export declare const FULL_QUERY_ALLOWED_KEYWORDS: readonly ["EXISTS", "ANY", "ALL", "SOME", "UNION", "INTERSECT", "EXCEPT", "IF"];
|
|
15
21
|
/**
|
|
16
22
|
* Safe SQL functions allowed in expressions, organized by category
|
|
17
23
|
*/
|
|
@@ -29,7 +35,7 @@ export declare const ALLOWED_SQL_FUNCTIONS: {
|
|
|
29
35
|
/**
|
|
30
36
|
* Validation context - affects what's allowed
|
|
31
37
|
*/
|
|
32
|
-
export type SQLValidationContext = 'where_clause' | 'order_by' | 'aggregate' | 'field_reference';
|
|
38
|
+
export type SQLValidationContext = 'where_clause' | 'order_by' | 'aggregate' | 'field_reference' | 'full_query';
|
|
33
39
|
/**
|
|
34
40
|
* Validation result with detailed error information
|
|
35
41
|
*/
|
|
@@ -117,9 +123,30 @@ export declare class SQLExpressionValidator {
|
|
|
117
123
|
* Validate field references exist in entity (lenient mode - just for logging)
|
|
118
124
|
*/
|
|
119
125
|
private checkFieldReferences;
|
|
126
|
+
/**
|
|
127
|
+
* Strip SQL comments (single-line -- and multi-line block comments) from a query.
|
|
128
|
+
* Used by full_query context to allow agent-generated header comments
|
|
129
|
+
* without triggering the comment injection check.
|
|
130
|
+
*/
|
|
131
|
+
private stripSQLComments;
|
|
120
132
|
/**
|
|
121
133
|
* Escape special regex characters in a string
|
|
122
134
|
*/
|
|
123
135
|
private escapeRegex;
|
|
136
|
+
/**
|
|
137
|
+
* Normalize literal escape sequences in SQL strings.
|
|
138
|
+
* Agent-generated SQL sometimes arrives with literal \n, \r, \t sequences
|
|
139
|
+
* (backslash + letter) instead of actual whitespace characters. This happens
|
|
140
|
+
* when JSON is double-escaped or the SQL passes through a transport layer
|
|
141
|
+
* that doesn't interpret escape sequences. Without normalization, comment
|
|
142
|
+
* stripping fails because the regex expects real newlines.
|
|
143
|
+
*/
|
|
144
|
+
private normalizeSQLWhitespace;
|
|
145
|
+
/**
|
|
146
|
+
* Validate a full SQL query (SELECT or WITH/CTE statement).
|
|
147
|
+
* Blocks mutations, dangerous operations, and multi-statement injection.
|
|
148
|
+
* Allows SELECT, subqueries, set operations, and SQL comments.
|
|
149
|
+
*/
|
|
150
|
+
validateFullQuery(sql: string): SQLValidationResult;
|
|
124
151
|
}
|
|
125
152
|
//# sourceMappingURL=SQLExpressionValidator.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SQLExpressionValidator.d.ts","sourceRoot":"","sources":["../src/SQLExpressionValidator.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"SQLExpressionValidator.d.ts","sourceRoot":"","sources":["../src/SQLExpressionValidator.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH;;GAEG;AACH,eAAO,MAAM,sBAAsB,2gBA0CzB,CAAC;AAEX;;;GAGG;AACH,eAAO,MAAM,2BAA2B,iFAS9B,CAAC;AAEX;;GAEG;AACH,eAAO,MAAM,qBAAqB;;;;;;;;;;CA2BxB,CAAC;AAEX;;GAEG;AACH,MAAM,MAAM,oBAAoB,GAC5B,cAAc,GACd,UAAU,GACV,WAAW,GACX,iBAAiB,GACjB,YAAY,CAAC;AAEjB;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,+CAA+C;IAC/C,KAAK,EAAE,OAAO,CAAC;IACf,yCAAyC;IACzC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,2DAA2D;IAC3D,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,iCAAiC;IACjC,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,gDAAgD;IAChD,OAAO,EAAE,oBAAoB,CAAC;IAE9B,4EAA4E;IAC5E,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IAExB,wHAAwH;IACxH,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAE3B,iFAAiF;IACjF,eAAe,CAAC,EAAE,OAAO,CAAC;IAE1B,+CAA+C;IAC/C,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAC;IAE7B,qCAAqC;IACrC,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAC;CAC9B;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,qBAAa,sBAAsB;IACjC,OAAO,CAAC,MAAM,CAAC,SAAS,CAAyB;IAEjD,OAAO;IAEP;;OAEG;IACH,WAAkB,QAAQ,IAAI,sBAAsB,CAKnD;IAED;;;;;;OAMG;IACI,QAAQ,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,oBAAoB,GAAG,mBAAmB;IAoCvF;;;OAGG;IACH,OAAO,CAAC,oBAAoB;IAM5B;;OAEG;IACH,OAAO,CAAC,sBAAsB;IAoE9B;;OAEG;IACH,OAAO,CAAC,kBAAkB;IA2B1B;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAiCzB;;OAEG;IACH,OAAO,CAAC,oBAAoB;IA4B5B;;;;OAIG;IACH,OAAO,CAAC,gBAAgB;IAMxB;;OAEG;IACH,OAAO,CAAC,WAAW;IAInB;;;;;;;OAOG;IACH,OAAO,CAAC,sBAAsB;IAQ9B;;;;OAIG;IACI,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,mBAAmB;CAO3D"}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @fileoverview Unified SQL Expression Validation
|
|
2
|
+
* @fileoverview Unified SQL Expression and Query Validation
|
|
3
3
|
*
|
|
4
|
-
* Central utility for validating user-provided SQL expressions
|
|
5
|
-
* Used by RunView, aggregates, smart filters,
|
|
4
|
+
* Central utility for validating user-provided SQL expressions and full queries
|
|
5
|
+
* against injection attacks. Used by RunView, aggregates, smart filters, ad-hoc
|
|
6
|
+
* query execution, and any other feature accepting SQL input.
|
|
6
7
|
*
|
|
7
8
|
* Located in MJGlobal (lowest-level package) so all packages can use it.
|
|
8
9
|
*
|
|
@@ -41,6 +42,18 @@ export const DANGEROUS_SQL_KEYWORDS = [
|
|
|
41
42
|
// System operations
|
|
42
43
|
'SHUTDOWN', 'RECONFIGURE'
|
|
43
44
|
];
|
|
45
|
+
/**
|
|
46
|
+
* Keywords from DANGEROUS_SQL_KEYWORDS that are legitimate in full SELECT queries.
|
|
47
|
+
* These are only unblocked when context is 'full_query'.
|
|
48
|
+
*/
|
|
49
|
+
export const FULL_QUERY_ALLOWED_KEYWORDS = [
|
|
50
|
+
// Subquery operators — valid in WHERE EXISTS(...), x > ANY(...)
|
|
51
|
+
'EXISTS', 'ANY', 'ALL', 'SOME',
|
|
52
|
+
// Set operations — valid for UNION/INTERSECT/EXCEPT queries
|
|
53
|
+
'UNION', 'INTERSECT', 'EXCEPT',
|
|
54
|
+
// IIF() uses IF internally, CASE WHEN patterns are common
|
|
55
|
+
'IF',
|
|
56
|
+
];
|
|
44
57
|
/**
|
|
45
58
|
* Safe SQL functions allowed in expressions, organized by category
|
|
46
59
|
*/
|
|
@@ -117,10 +130,13 @@ export class SQLExpressionValidator {
|
|
|
117
130
|
const dangerCheck = this.checkDangerousPatterns(withoutStrings, options);
|
|
118
131
|
if (!dangerCheck.valid)
|
|
119
132
|
return dangerCheck;
|
|
120
|
-
// Step 3: Validate function names are in allowlist
|
|
121
|
-
|
|
122
|
-
if (
|
|
123
|
-
|
|
133
|
+
// Step 3: Validate function names are in allowlist (skip for full queries —
|
|
134
|
+
// the function allowlist is designed for expression fragments, not full SQL statements)
|
|
135
|
+
if (options.context !== 'full_query') {
|
|
136
|
+
const functionCheck = this.checkFunctionNames(withoutStrings, options);
|
|
137
|
+
if (!functionCheck.valid)
|
|
138
|
+
return functionCheck;
|
|
139
|
+
}
|
|
124
140
|
// Step 4: Context-specific validation
|
|
125
141
|
const contextCheck = this.checkContextRules(withoutStrings, options);
|
|
126
142
|
if (!contextCheck.valid)
|
|
@@ -144,20 +160,42 @@ export class SQLExpressionValidator {
|
|
|
144
160
|
* Check for dangerous SQL patterns that indicate injection attempts
|
|
145
161
|
*/
|
|
146
162
|
checkDangerousPatterns(expression, options) {
|
|
147
|
-
const
|
|
163
|
+
const isFullQuery = options.context === 'full_query';
|
|
148
164
|
// Build blocked list - explicitly typed as string[] for mutability
|
|
149
|
-
|
|
165
|
+
let blocked = [...DANGEROUS_SQL_KEYWORDS];
|
|
150
166
|
if (options.additionalBlocked) {
|
|
151
167
|
blocked.push(...options.additionalBlocked);
|
|
152
168
|
}
|
|
153
|
-
//
|
|
154
|
-
if (
|
|
169
|
+
// For full_query context, remove keywords that are legitimate in SELECT statements
|
|
170
|
+
if (isFullQuery) {
|
|
171
|
+
const allowedSet = new Set(FULL_QUERY_ALLOWED_KEYWORDS.map(k => k.toUpperCase()));
|
|
172
|
+
blocked = blocked.filter(kw => !allowedSet.has(kw.toUpperCase()));
|
|
173
|
+
}
|
|
174
|
+
// Add SELECT to blocked unless context allows it (prevents subqueries in expressions)
|
|
175
|
+
if (!isFullQuery && !options.allowSubqueries && !blocked.includes('SELECT')) {
|
|
155
176
|
blocked.push('SELECT');
|
|
156
177
|
}
|
|
178
|
+
// For full_query, strip comments before keyword checking (agent SQL has header comment blocks).
|
|
179
|
+
// For expressions, comments are still rejected outright as injection vectors.
|
|
180
|
+
let textToCheck;
|
|
181
|
+
if (isFullQuery) {
|
|
182
|
+
textToCheck = this.stripSQLComments(expression).toUpperCase();
|
|
183
|
+
}
|
|
184
|
+
else {
|
|
185
|
+
const upper = expression.toUpperCase();
|
|
186
|
+
if (upper.includes('--') || upper.includes('/*') || upper.includes('*/')) {
|
|
187
|
+
return {
|
|
188
|
+
valid: false,
|
|
189
|
+
error: 'Comments are not allowed in SQL expressions',
|
|
190
|
+
trigger: 'comment'
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
textToCheck = upper;
|
|
194
|
+
}
|
|
157
195
|
for (const keyword of blocked) {
|
|
158
196
|
// Use word boundaries to avoid false positives (e.g., "DESCRIPTION" containing "EXEC")
|
|
159
197
|
const pattern = new RegExp(`\\b${this.escapeRegex(keyword)}\\b`, 'i');
|
|
160
|
-
if (pattern.test(
|
|
198
|
+
if (pattern.test(textToCheck)) {
|
|
161
199
|
return {
|
|
162
200
|
valid: false,
|
|
163
201
|
error: `Dangerous SQL keyword detected: ${keyword}`,
|
|
@@ -166,16 +204,14 @@ export class SQLExpressionValidator {
|
|
|
166
204
|
};
|
|
167
205
|
}
|
|
168
206
|
}
|
|
169
|
-
// Check
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
// Check statement terminator (prevents multi-statement injection)
|
|
178
|
-
if (expression.includes(';')) {
|
|
207
|
+
// Check statement terminator (prevents multi-statement injection).
|
|
208
|
+
// For full_query context, strip comments first (a trailing semicolon may be followed by
|
|
209
|
+
// an inline comment like `ORDER BY x DESC; -- highest first`), then strip the trailing
|
|
210
|
+
// semicolon. Only reject if semicolons remain mid-statement, indicating injection.
|
|
211
|
+
const textForSemicolonCheck = isFullQuery
|
|
212
|
+
? this.stripSQLComments(expression).replace(/;\s*$/, '') // strip comments then trailing semicolon
|
|
213
|
+
: expression;
|
|
214
|
+
if (textForSemicolonCheck.includes(';')) {
|
|
179
215
|
return {
|
|
180
216
|
valid: false,
|
|
181
217
|
error: 'Semicolons are not allowed in SQL expressions',
|
|
@@ -228,6 +264,18 @@ export class SQLExpressionValidator {
|
|
|
228
264
|
};
|
|
229
265
|
}
|
|
230
266
|
}
|
|
267
|
+
// For full_query context, the query must start with SELECT or WITH (CTE)
|
|
268
|
+
if (options.context === 'full_query') {
|
|
269
|
+
const stripped = this.stripSQLComments(expression).trim();
|
|
270
|
+
const upper = stripped.toUpperCase();
|
|
271
|
+
if (!upper.startsWith('SELECT') && !upper.startsWith('WITH')) {
|
|
272
|
+
return {
|
|
273
|
+
valid: false,
|
|
274
|
+
error: 'Ad-hoc query must start with SELECT or WITH',
|
|
275
|
+
suggestion: 'Only SELECT statements and CTEs (WITH ... AS) are allowed'
|
|
276
|
+
};
|
|
277
|
+
}
|
|
278
|
+
}
|
|
231
279
|
return { valid: true };
|
|
232
280
|
}
|
|
233
281
|
/**
|
|
@@ -256,11 +304,48 @@ export class SQLExpressionValidator {
|
|
|
256
304
|
// For now, we allow it to pass
|
|
257
305
|
}
|
|
258
306
|
}
|
|
307
|
+
/**
|
|
308
|
+
* Strip SQL comments (single-line -- and multi-line block comments) from a query.
|
|
309
|
+
* Used by full_query context to allow agent-generated header comments
|
|
310
|
+
* without triggering the comment injection check.
|
|
311
|
+
*/
|
|
312
|
+
stripSQLComments(sql) {
|
|
313
|
+
return sql
|
|
314
|
+
.replace(/--[^\n]*/g, '') // Single-line comments
|
|
315
|
+
.replace(/\/\*[\s\S]*?\*\//g, ''); // Block comments
|
|
316
|
+
}
|
|
259
317
|
/**
|
|
260
318
|
* Escape special regex characters in a string
|
|
261
319
|
*/
|
|
262
320
|
escapeRegex(str) {
|
|
263
321
|
return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
264
322
|
}
|
|
323
|
+
/**
|
|
324
|
+
* Normalize literal escape sequences in SQL strings.
|
|
325
|
+
* Agent-generated SQL sometimes arrives with literal \n, \r, \t sequences
|
|
326
|
+
* (backslash + letter) instead of actual whitespace characters. This happens
|
|
327
|
+
* when JSON is double-escaped or the SQL passes through a transport layer
|
|
328
|
+
* that doesn't interpret escape sequences. Without normalization, comment
|
|
329
|
+
* stripping fails because the regex expects real newlines.
|
|
330
|
+
*/
|
|
331
|
+
normalizeSQLWhitespace(sql) {
|
|
332
|
+
return sql
|
|
333
|
+
.replace(/\\r\\n/g, '\n') // Literal \r\n → newline
|
|
334
|
+
.replace(/\\n/g, '\n') // Literal \n → newline
|
|
335
|
+
.replace(/\\r/g, '\r') // Literal \r → carriage return
|
|
336
|
+
.replace(/\\t/g, '\t'); // Literal \t → tab
|
|
337
|
+
}
|
|
338
|
+
/**
|
|
339
|
+
* Validate a full SQL query (SELECT or WITH/CTE statement).
|
|
340
|
+
* Blocks mutations, dangerous operations, and multi-statement injection.
|
|
341
|
+
* Allows SELECT, subqueries, set operations, and SQL comments.
|
|
342
|
+
*/
|
|
343
|
+
validateFullQuery(sql) {
|
|
344
|
+
// Normalize literal escape sequences before validation — agent-generated
|
|
345
|
+
// SQL may arrive with literal \n instead of real newlines, which breaks
|
|
346
|
+
// comment stripping and the "must start with SELECT" check.
|
|
347
|
+
const normalized = this.normalizeSQLWhitespace(sql);
|
|
348
|
+
return this.validate(normalized, { context: 'full_query' });
|
|
349
|
+
}
|
|
265
350
|
}
|
|
266
351
|
//# sourceMappingURL=SQLExpressionValidator.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SQLExpressionValidator.js","sourceRoot":"","sources":["../src/SQLExpressionValidator.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"SQLExpressionValidator.js","sourceRoot":"","sources":["../src/SQLExpressionValidator.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SQLExpressionValidator.security.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/SQLExpressionValidator.security.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,328 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach } from 'vitest';
|
|
2
|
+
import { SQLExpressionValidator } from '../SQLExpressionValidator.js';
|
|
3
|
+
/**
|
|
4
|
+
* Adversarial security tests for SQLExpressionValidator.
|
|
5
|
+
* These tests simulate real-world SQL injection attempts that an attacker
|
|
6
|
+
* (or a misguided LLM) might produce.
|
|
7
|
+
*/
|
|
8
|
+
describe('SQLExpressionValidator - Security', () => {
|
|
9
|
+
let validator;
|
|
10
|
+
beforeEach(() => {
|
|
11
|
+
validator = SQLExpressionValidator.Instance;
|
|
12
|
+
});
|
|
13
|
+
// ---------------------------------------------------------------
|
|
14
|
+
// Classic SQL injection patterns (full_query context)
|
|
15
|
+
// ---------------------------------------------------------------
|
|
16
|
+
describe('SQL injection attempts (full_query)', () => {
|
|
17
|
+
const ctx = { context: 'full_query' };
|
|
18
|
+
it('should block tautology + stacked DROP', () => {
|
|
19
|
+
const r = validator.validateFullQuery("SELECT * FROM Users WHERE 1=1; DROP TABLE Users");
|
|
20
|
+
expect(r.valid).toBe(false);
|
|
21
|
+
// DROP is detected before semicolon in the keyword scan
|
|
22
|
+
expect(r.trigger).toBe('DROP');
|
|
23
|
+
});
|
|
24
|
+
it('should block UNION-based data exfiltration', () => {
|
|
25
|
+
// This is valid in full_query because UNION is allowed—
|
|
26
|
+
// BUT it must still start with SELECT. The attack vector here
|
|
27
|
+
// is actually fine for full_query (UNION is legitimate).
|
|
28
|
+
// The real guard is that only SELECT queries can be submitted.
|
|
29
|
+
const r = validator.validateFullQuery("SELECT 1 UNION SELECT password FROM sys.sql_logins");
|
|
30
|
+
// UNION is allowed in full_query, so this is valid from a syntax perspective.
|
|
31
|
+
// The protection is that ad-hoc queries run on a read-only connection.
|
|
32
|
+
expect(r.valid).toBe(true);
|
|
33
|
+
});
|
|
34
|
+
it('should block stacked DELETE after SELECT', () => {
|
|
35
|
+
const r = validator.validateFullQuery("SELECT 1; DELETE FROM Users");
|
|
36
|
+
expect(r.valid).toBe(false);
|
|
37
|
+
// DELETE is detected before semicolon in the keyword scan
|
|
38
|
+
expect(r.trigger).toBe('DELETE');
|
|
39
|
+
});
|
|
40
|
+
it('should block INSERT disguised after comment', () => {
|
|
41
|
+
const r = validator.validateFullQuery("SELECT 1 -- \nINSERT INTO Users (Name) VALUES ('hacked')");
|
|
42
|
+
// After stripping comments, "INSERT INTO Users..." is detected
|
|
43
|
+
expect(r.valid).toBe(false);
|
|
44
|
+
expect(r.trigger).toBe('INSERT');
|
|
45
|
+
});
|
|
46
|
+
it('should block EXEC sp_executesql', () => {
|
|
47
|
+
const r = validator.validateFullQuery("EXEC sp_executesql N'SELECT 1'");
|
|
48
|
+
expect(r.valid).toBe(false);
|
|
49
|
+
expect(r.trigger).toBe('EXEC');
|
|
50
|
+
});
|
|
51
|
+
it('should block EXECUTE xp_cmdshell', () => {
|
|
52
|
+
const r = validator.validateFullQuery("EXECUTE xp_cmdshell 'dir'");
|
|
53
|
+
expect(r.valid).toBe(false);
|
|
54
|
+
expect(r.trigger).toBe('EXECUTE');
|
|
55
|
+
});
|
|
56
|
+
it('should block WAITFOR DELAY (time-based blind injection)', () => {
|
|
57
|
+
const r = validator.validateFullQuery("SELECT 1 WHERE 1=1 WAITFOR DELAY '00:00:10'");
|
|
58
|
+
expect(r.valid).toBe(false);
|
|
59
|
+
expect(r.trigger).toBe('WAITFOR');
|
|
60
|
+
});
|
|
61
|
+
it('should block xp_cmdshell via keyword detection', () => {
|
|
62
|
+
const r = validator.validateFullQuery("SELECT 1; EXEC xp_cmdshell 'whoami'");
|
|
63
|
+
expect(r.valid).toBe(false);
|
|
64
|
+
// EXEC is detected before semicolon in the keyword scan
|
|
65
|
+
expect(r.trigger).toBe('EXEC');
|
|
66
|
+
});
|
|
67
|
+
it('should block OPENROWSET file access', () => {
|
|
68
|
+
const r = validator.validateFullQuery("SELECT * FROM OPENROWSET('SQLNCLI', 'Server=evil;', 'SELECT 1')");
|
|
69
|
+
expect(r.valid).toBe(false);
|
|
70
|
+
expect(r.trigger).toBe('OPENROWSET');
|
|
71
|
+
});
|
|
72
|
+
it('should block OPENDATASOURCE', () => {
|
|
73
|
+
const r = validator.validateFullQuery("SELECT * FROM OPENDATASOURCE('SQLNCLI', 'Data Source=evil;').db.dbo.Users");
|
|
74
|
+
expect(r.valid).toBe(false);
|
|
75
|
+
expect(r.trigger).toBe('OPENDATASOURCE');
|
|
76
|
+
});
|
|
77
|
+
it('should block BULK INSERT', () => {
|
|
78
|
+
const r = validator.validateFullQuery("BULK INSERT Users FROM '\\\\evil\\share\\data.csv'");
|
|
79
|
+
expect(r.valid).toBe(false);
|
|
80
|
+
// INSERT comes before BULK in the keyword scan order
|
|
81
|
+
expect(r.trigger).toBe('INSERT');
|
|
82
|
+
});
|
|
83
|
+
it('should block CREATE TABLE', () => {
|
|
84
|
+
const r = validator.validateFullQuery("CREATE TABLE Evil (ID INT)");
|
|
85
|
+
expect(r.valid).toBe(false);
|
|
86
|
+
});
|
|
87
|
+
it('should block ALTER TABLE', () => {
|
|
88
|
+
const r = validator.validateFullQuery("ALTER TABLE Users ADD HackedColumn NVARCHAR(100)");
|
|
89
|
+
expect(r.valid).toBe(false);
|
|
90
|
+
expect(r.trigger).toBe('ALTER');
|
|
91
|
+
});
|
|
92
|
+
it('should block GRANT privilege escalation', () => {
|
|
93
|
+
const r = validator.validateFullQuery("GRANT CONTROL ON DATABASE::mydb TO public");
|
|
94
|
+
expect(r.valid).toBe(false);
|
|
95
|
+
expect(r.trigger).toBe('GRANT');
|
|
96
|
+
});
|
|
97
|
+
it('should block REVOKE', () => {
|
|
98
|
+
const r = validator.validateFullQuery("REVOKE SELECT ON Users FROM someuser");
|
|
99
|
+
expect(r.valid).toBe(false);
|
|
100
|
+
expect(r.trigger).toBe('REVOKE');
|
|
101
|
+
});
|
|
102
|
+
it('should block DENY', () => {
|
|
103
|
+
const r = validator.validateFullQuery("DENY SELECT ON Users TO someuser");
|
|
104
|
+
expect(r.valid).toBe(false);
|
|
105
|
+
expect(r.trigger).toBe('DENY');
|
|
106
|
+
});
|
|
107
|
+
it('should block SHUTDOWN', () => {
|
|
108
|
+
const r = validator.validateFullQuery("SHUTDOWN WITH NOWAIT");
|
|
109
|
+
expect(r.valid).toBe(false);
|
|
110
|
+
expect(r.trigger).toBe('SHUTDOWN');
|
|
111
|
+
});
|
|
112
|
+
it('should block RECONFIGURE', () => {
|
|
113
|
+
const r = validator.validateFullQuery("RECONFIGURE WITH OVERRIDE");
|
|
114
|
+
expect(r.valid).toBe(false);
|
|
115
|
+
expect(r.trigger).toBe('RECONFIGURE');
|
|
116
|
+
});
|
|
117
|
+
it('should block statement not starting with SELECT/WITH', () => {
|
|
118
|
+
const r = validator.validateFullQuery("UPDATE Users SET IsAdmin = 1");
|
|
119
|
+
expect(r.valid).toBe(false);
|
|
120
|
+
expect(r.trigger).toBe('UPDATE');
|
|
121
|
+
});
|
|
122
|
+
it('should block MERGE statement', () => {
|
|
123
|
+
const r = validator.validateFullQuery("MERGE INTO Users AS t USING (SELECT 1 AS ID) AS s ON t.ID = s.ID WHEN MATCHED THEN DELETE");
|
|
124
|
+
expect(r.valid).toBe(false);
|
|
125
|
+
// DELETE comes before MERGE in the keyword scan order
|
|
126
|
+
expect(r.trigger).toBe('DELETE');
|
|
127
|
+
});
|
|
128
|
+
it('should block TRUNCATE TABLE', () => {
|
|
129
|
+
const r = validator.validateFullQuery("TRUNCATE TABLE Users");
|
|
130
|
+
expect(r.valid).toBe(false);
|
|
131
|
+
expect(r.trigger).toBe('TRUNCATE');
|
|
132
|
+
});
|
|
133
|
+
});
|
|
134
|
+
// ---------------------------------------------------------------
|
|
135
|
+
// Obfuscation and bypass attempts
|
|
136
|
+
// ---------------------------------------------------------------
|
|
137
|
+
describe('obfuscation and bypass attempts', () => {
|
|
138
|
+
it('should block keyword in mixed case (DrOp)', () => {
|
|
139
|
+
const r = validator.validateFullQuery("DrOp TaBlE Users");
|
|
140
|
+
expect(r.valid).toBe(false);
|
|
141
|
+
});
|
|
142
|
+
it('should block with extra whitespace around dangerous keyword', () => {
|
|
143
|
+
const r = validator.validateFullQuery(" DELETE FROM Users ");
|
|
144
|
+
expect(r.valid).toBe(false);
|
|
145
|
+
expect(r.trigger).toBe('DELETE');
|
|
146
|
+
});
|
|
147
|
+
it('should block multi-statement via semicolon with whitespace', () => {
|
|
148
|
+
const r = validator.validateFullQuery("SELECT 1 ; DROP TABLE Users");
|
|
149
|
+
expect(r.valid).toBe(false);
|
|
150
|
+
// DROP is detected before semicolon in the keyword scan
|
|
151
|
+
expect(r.trigger).toBe('DROP');
|
|
152
|
+
});
|
|
153
|
+
it('should block newline-separated stacked statements', () => {
|
|
154
|
+
const r = validator.validateFullQuery("SELECT 1;\nDROP TABLE Users");
|
|
155
|
+
expect(r.valid).toBe(false);
|
|
156
|
+
// DROP is detected before semicolon in the keyword scan
|
|
157
|
+
expect(r.trigger).toBe('DROP');
|
|
158
|
+
});
|
|
159
|
+
it('should not be fooled by tab characters in keywords', () => {
|
|
160
|
+
const r = validator.validateFullQuery("SELECT 1;\tDELETE FROM Users");
|
|
161
|
+
expect(r.valid).toBe(false);
|
|
162
|
+
// DELETE is detected before semicolon in the keyword scan
|
|
163
|
+
expect(r.trigger).toBe('DELETE');
|
|
164
|
+
});
|
|
165
|
+
});
|
|
166
|
+
// ---------------------------------------------------------------
|
|
167
|
+
// String literal false-positive prevention
|
|
168
|
+
// ---------------------------------------------------------------
|
|
169
|
+
describe('string literal false-positive prevention', () => {
|
|
170
|
+
it('should allow DROP inside a string literal', () => {
|
|
171
|
+
const r = validator.validateFullQuery("SELECT * FROM __mj.vwLogs WHERE Message = 'We need to DROP the old approach'");
|
|
172
|
+
expect(r.valid).toBe(true);
|
|
173
|
+
});
|
|
174
|
+
it('should allow INSERT inside a string literal', () => {
|
|
175
|
+
const r = validator.validateFullQuery("SELECT * FROM __mj.vwAuditLog WHERE Action = 'INSERT completed'");
|
|
176
|
+
expect(r.valid).toBe(true);
|
|
177
|
+
});
|
|
178
|
+
it('should allow DELETE inside a string literal', () => {
|
|
179
|
+
const r = validator.validateFullQuery("SELECT * FROM __mj.vwUsers WHERE Bio LIKE '%DELETE old records%'");
|
|
180
|
+
expect(r.valid).toBe(true);
|
|
181
|
+
});
|
|
182
|
+
it('should allow EXEC inside a string literal', () => {
|
|
183
|
+
const r = validator.validateFullQuery("SELECT * FROM __mj.vwJobs WHERE Description = 'EXEC the plan'");
|
|
184
|
+
expect(r.valid).toBe(true);
|
|
185
|
+
});
|
|
186
|
+
it('should still block REAL DROP outside string context', () => {
|
|
187
|
+
const r = validator.validateFullQuery("SELECT 'safe text' FROM Users; DROP TABLE Users");
|
|
188
|
+
expect(r.valid).toBe(false);
|
|
189
|
+
// DROP is detected before semicolon in the keyword scan
|
|
190
|
+
expect(r.trigger).toBe('DROP');
|
|
191
|
+
});
|
|
192
|
+
});
|
|
193
|
+
// ---------------------------------------------------------------
|
|
194
|
+
// Expression-level injection (where_clause context)
|
|
195
|
+
// ---------------------------------------------------------------
|
|
196
|
+
describe('expression-level injection (where_clause)', () => {
|
|
197
|
+
const ctx = { context: 'where_clause' };
|
|
198
|
+
it('should block subquery without allowSubqueries', () => {
|
|
199
|
+
const r = validator.validate("ID IN (SELECT ID FROM Users WHERE IsAdmin = 1)", ctx);
|
|
200
|
+
expect(r.valid).toBe(false);
|
|
201
|
+
expect(r.trigger).toBe('SELECT');
|
|
202
|
+
});
|
|
203
|
+
it('should block UNION injection in WHERE clause', () => {
|
|
204
|
+
const r = validator.validate("1=1 UNION SELECT password FROM sys.sql_logins", ctx);
|
|
205
|
+
expect(r.valid).toBe(false);
|
|
206
|
+
expect(r.trigger).toBe('UNION');
|
|
207
|
+
});
|
|
208
|
+
it('should block comment injection in WHERE clause', () => {
|
|
209
|
+
const r = validator.validate("Status = 'Active' -- OR 1=1", ctx);
|
|
210
|
+
expect(r.valid).toBe(false);
|
|
211
|
+
expect(r.trigger).toBe('comment');
|
|
212
|
+
});
|
|
213
|
+
it('should block block comment injection in WHERE clause', () => {
|
|
214
|
+
const r = validator.validate("Status = 'Active' /* OR 1=1 */", ctx);
|
|
215
|
+
expect(r.valid).toBe(false);
|
|
216
|
+
expect(r.trigger).toBe('comment');
|
|
217
|
+
});
|
|
218
|
+
it('should block semicolon injection in WHERE clause', () => {
|
|
219
|
+
const r = validator.validate("1=1; DROP TABLE Users --", ctx);
|
|
220
|
+
expect(r.valid).toBe(false);
|
|
221
|
+
// Either semicolon or comment should trigger
|
|
222
|
+
});
|
|
223
|
+
it('should block EXEC in WHERE clause', () => {
|
|
224
|
+
const r = validator.validate("1=1 AND EXEC sp_help", ctx);
|
|
225
|
+
expect(r.valid).toBe(false);
|
|
226
|
+
expect(r.trigger).toBe('EXEC');
|
|
227
|
+
});
|
|
228
|
+
it('should block WAITFOR in WHERE clause', () => {
|
|
229
|
+
const r = validator.validate("1=1 WAITFOR DELAY '00:00:05'", ctx);
|
|
230
|
+
expect(r.valid).toBe(false);
|
|
231
|
+
expect(r.trigger).toBe('WAITFOR');
|
|
232
|
+
});
|
|
233
|
+
it('should block CREATE in WHERE clause', () => {
|
|
234
|
+
const r = validator.validate("1=1 CREATE TABLE Evil (ID INT)", ctx);
|
|
235
|
+
expect(r.valid).toBe(false);
|
|
236
|
+
expect(r.trigger).toBe('CREATE');
|
|
237
|
+
});
|
|
238
|
+
});
|
|
239
|
+
// ---------------------------------------------------------------
|
|
240
|
+
// Edge cases
|
|
241
|
+
// ---------------------------------------------------------------
|
|
242
|
+
describe('edge cases', () => {
|
|
243
|
+
it('should reject empty string', () => {
|
|
244
|
+
const r = validator.validateFullQuery('');
|
|
245
|
+
expect(r.valid).toBe(false);
|
|
246
|
+
});
|
|
247
|
+
it('should reject whitespace-only string', () => {
|
|
248
|
+
const r = validator.validateFullQuery(' \n\t ');
|
|
249
|
+
expect(r.valid).toBe(false);
|
|
250
|
+
});
|
|
251
|
+
it('should handle very long SELECT query', () => {
|
|
252
|
+
// Build a long but valid query
|
|
253
|
+
const conditions = Array.from({ length: 100 }, (_, i) => `Field${i} = ${i}`).join(' AND ');
|
|
254
|
+
const sql = `SELECT * FROM __mj.vwUsers WHERE ${conditions}`;
|
|
255
|
+
const r = validator.validateFullQuery(sql);
|
|
256
|
+
expect(r.valid).toBe(true);
|
|
257
|
+
});
|
|
258
|
+
it('should handle deeply nested subqueries', () => {
|
|
259
|
+
const sql = `
|
|
260
|
+
SELECT * FROM __mj.vwUsers
|
|
261
|
+
WHERE ID IN (
|
|
262
|
+
SELECT UserID FROM __mj.vwUserRoles
|
|
263
|
+
WHERE RoleID IN (
|
|
264
|
+
SELECT RoleID FROM __mj.vwRoles
|
|
265
|
+
WHERE Name IN (
|
|
266
|
+
SELECT RoleName FROM __mj.vwDefaultRoles
|
|
267
|
+
)
|
|
268
|
+
)
|
|
269
|
+
)
|
|
270
|
+
`;
|
|
271
|
+
const r = validator.validateFullQuery(sql);
|
|
272
|
+
expect(r.valid).toBe(true);
|
|
273
|
+
});
|
|
274
|
+
it('should handle query with only comments (no actual SQL)', () => {
|
|
275
|
+
const sql = `
|
|
276
|
+
-- This is just a comment
|
|
277
|
+
/* Another comment */
|
|
278
|
+
`;
|
|
279
|
+
const r = validator.validateFullQuery(sql);
|
|
280
|
+
// After stripping comments, there's no SELECT/WITH
|
|
281
|
+
expect(r.valid).toBe(false);
|
|
282
|
+
});
|
|
283
|
+
it('should handle query with unicode characters in string literals', () => {
|
|
284
|
+
const sql = "SELECT * FROM __mj.vwUsers WHERE Name = N'Ünïcödé Tëst'";
|
|
285
|
+
const r = validator.validateFullQuery(sql);
|
|
286
|
+
expect(r.valid).toBe(true);
|
|
287
|
+
});
|
|
288
|
+
it('should handle query with escaped single quotes', () => {
|
|
289
|
+
const sql = "SELECT * FROM __mj.vwUsers WHERE Name = 'O''Brien'";
|
|
290
|
+
const r = validator.validateFullQuery(sql);
|
|
291
|
+
expect(r.valid).toBe(true);
|
|
292
|
+
});
|
|
293
|
+
it('should handle query with numeric literals', () => {
|
|
294
|
+
const sql = "SELECT * FROM __mj.vwOrders WHERE Total > 1000.50 AND Quantity < 100";
|
|
295
|
+
const r = validator.validateFullQuery(sql);
|
|
296
|
+
expect(r.valid).toBe(true);
|
|
297
|
+
});
|
|
298
|
+
it('should handle query with multiple CTEs', () => {
|
|
299
|
+
const sql = `
|
|
300
|
+
WITH CTE1 AS (SELECT ID FROM __mj.vwUsers),
|
|
301
|
+
CTE2 AS (SELECT UserID FROM __mj.vwUserRoles)
|
|
302
|
+
SELECT * FROM CTE1 INNER JOIN CTE2 ON CTE1.ID = CTE2.UserID
|
|
303
|
+
`;
|
|
304
|
+
const r = validator.validateFullQuery(sql);
|
|
305
|
+
expect(r.valid).toBe(true);
|
|
306
|
+
});
|
|
307
|
+
it('should handle CROSS APPLY and OUTER APPLY', () => {
|
|
308
|
+
const sql = `
|
|
309
|
+
SELECT u.Name, r.RoleName
|
|
310
|
+
FROM __mj.vwUsers u
|
|
311
|
+
CROSS APPLY (SELECT TOP 1 RoleName FROM __mj.vwUserRoles WHERE UserID = u.ID) r
|
|
312
|
+
`;
|
|
313
|
+
const r = validator.validateFullQuery(sql);
|
|
314
|
+
expect(r.valid).toBe(true);
|
|
315
|
+
});
|
|
316
|
+
it('should handle window functions', () => {
|
|
317
|
+
const sql = `
|
|
318
|
+
SELECT Name,
|
|
319
|
+
ROW_NUMBER() OVER (PARTITION BY Department ORDER BY HireDate) AS RowNum,
|
|
320
|
+
RANK() OVER (ORDER BY Salary DESC) AS SalaryRank
|
|
321
|
+
FROM __mj.vwEmployees
|
|
322
|
+
`;
|
|
323
|
+
const r = validator.validateFullQuery(sql);
|
|
324
|
+
expect(r.valid).toBe(true);
|
|
325
|
+
});
|
|
326
|
+
});
|
|
327
|
+
});
|
|
328
|
+
//# sourceMappingURL=SQLExpressionValidator.security.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SQLExpressionValidator.security.test.js","sourceRoot":"","sources":["../../src/__tests__/SQLExpressionValidator.security.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SQLExpressionValidator.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/SQLExpressionValidator.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,350 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach } from 'vitest';
|
|
2
|
+
import { SQLExpressionValidator, DANGEROUS_SQL_KEYWORDS, FULL_QUERY_ALLOWED_KEYWORDS, ALLOWED_SQL_FUNCTIONS, } from '../SQLExpressionValidator.js';
|
|
3
|
+
describe('SQLExpressionValidator', () => {
|
|
4
|
+
let validator;
|
|
5
|
+
beforeEach(() => {
|
|
6
|
+
validator = SQLExpressionValidator.Instance;
|
|
7
|
+
});
|
|
8
|
+
describe('singleton', () => {
|
|
9
|
+
it('should return the same instance', () => {
|
|
10
|
+
const a = SQLExpressionValidator.Instance;
|
|
11
|
+
const b = SQLExpressionValidator.Instance;
|
|
12
|
+
expect(a).toBe(b);
|
|
13
|
+
});
|
|
14
|
+
});
|
|
15
|
+
// ---------------------------------------------------------------
|
|
16
|
+
// full_query context
|
|
17
|
+
// ---------------------------------------------------------------
|
|
18
|
+
describe('full_query context', () => {
|
|
19
|
+
const ctx = { context: 'full_query' };
|
|
20
|
+
describe('valid queries', () => {
|
|
21
|
+
it('should accept a simple SELECT', () => {
|
|
22
|
+
const r = validator.validate('SELECT TOP 10 * FROM Users', ctx);
|
|
23
|
+
expect(r.valid).toBe(true);
|
|
24
|
+
});
|
|
25
|
+
it('should accept SELECT with JOINs, WHERE, GROUP BY, ORDER BY', () => {
|
|
26
|
+
const sql = `
|
|
27
|
+
SELECT a.Name, COUNT(r.ID) AS TotalRuns
|
|
28
|
+
FROM __mj.vwAIAgents a
|
|
29
|
+
INNER JOIN __mj.vwAIAgentRuns r ON r.AgentID = a.ID
|
|
30
|
+
WHERE r.StartedAt >= DATEADD(DAY, -30, GETDATE())
|
|
31
|
+
GROUP BY a.Name
|
|
32
|
+
ORDER BY TotalRuns DESC
|
|
33
|
+
`;
|
|
34
|
+
const r = validator.validate(sql, ctx);
|
|
35
|
+
expect(r.valid).toBe(true);
|
|
36
|
+
});
|
|
37
|
+
it('should accept WITH (CTE) statement', () => {
|
|
38
|
+
const sql = `
|
|
39
|
+
WITH ActiveAgents AS (
|
|
40
|
+
SELECT AgentID, COUNT(*) AS RunCount
|
|
41
|
+
FROM __mj.vwAIAgentRuns
|
|
42
|
+
GROUP BY AgentID
|
|
43
|
+
)
|
|
44
|
+
SELECT a.Name, aa.RunCount
|
|
45
|
+
FROM __mj.vwAIAgents a
|
|
46
|
+
INNER JOIN ActiveAgents aa ON aa.AgentID = a.ID
|
|
47
|
+
`;
|
|
48
|
+
const r = validator.validate(sql, ctx);
|
|
49
|
+
expect(r.valid).toBe(true);
|
|
50
|
+
});
|
|
51
|
+
it('should accept SELECT with EXISTS subquery', () => {
|
|
52
|
+
const sql = `
|
|
53
|
+
SELECT * FROM __mj.vwUsers u
|
|
54
|
+
WHERE EXISTS (SELECT 1 FROM __mj.vwUserRoles ur WHERE ur.UserID = u.ID)
|
|
55
|
+
`;
|
|
56
|
+
const r = validator.validate(sql, ctx);
|
|
57
|
+
expect(r.valid).toBe(true);
|
|
58
|
+
});
|
|
59
|
+
it('should accept UNION queries', () => {
|
|
60
|
+
const sql = `
|
|
61
|
+
SELECT Name, 'Agent' AS Type FROM __mj.vwAIAgents
|
|
62
|
+
UNION ALL
|
|
63
|
+
SELECT Name, 'Model' AS Type FROM __mj.vwAIModels
|
|
64
|
+
`;
|
|
65
|
+
const r = validator.validate(sql, ctx);
|
|
66
|
+
expect(r.valid).toBe(true);
|
|
67
|
+
});
|
|
68
|
+
it('should accept INTERSECT queries', () => {
|
|
69
|
+
const sql = `
|
|
70
|
+
SELECT UserID FROM __mj.vwUserRoles WHERE RoleID = 'abc'
|
|
71
|
+
INTERSECT
|
|
72
|
+
SELECT UserID FROM __mj.vwUserRoles WHERE RoleID = 'def'
|
|
73
|
+
`;
|
|
74
|
+
const r = validator.validate(sql, ctx);
|
|
75
|
+
expect(r.valid).toBe(true);
|
|
76
|
+
});
|
|
77
|
+
it('should accept EXCEPT queries', () => {
|
|
78
|
+
const sql = `
|
|
79
|
+
SELECT UserID FROM __mj.vwUsers
|
|
80
|
+
EXCEPT
|
|
81
|
+
SELECT UserID FROM __mj.vwUserRoles
|
|
82
|
+
`;
|
|
83
|
+
const r = validator.validate(sql, ctx);
|
|
84
|
+
expect(r.valid).toBe(true);
|
|
85
|
+
});
|
|
86
|
+
it('should accept SQL with single-line comments (stripped, not rejected)', () => {
|
|
87
|
+
const sql = `
|
|
88
|
+
-- ============================================================
|
|
89
|
+
-- Member Event Attendance Summary
|
|
90
|
+
-- ============================================================
|
|
91
|
+
SELECT TOP 100 m.FirstName, m.LastName
|
|
92
|
+
FROM __mj.vwMembers m
|
|
93
|
+
`;
|
|
94
|
+
const r = validator.validate(sql, ctx);
|
|
95
|
+
expect(r.valid).toBe(true);
|
|
96
|
+
});
|
|
97
|
+
it('should accept SQL with block comments', () => {
|
|
98
|
+
const sql = `
|
|
99
|
+
/* Agent performance query */
|
|
100
|
+
SELECT a.Name FROM __mj.vwAIAgents a
|
|
101
|
+
`;
|
|
102
|
+
const r = validator.validate(sql, ctx);
|
|
103
|
+
expect(r.valid).toBe(true);
|
|
104
|
+
});
|
|
105
|
+
it('should accept WHERE x > ANY(...)', () => {
|
|
106
|
+
const sql = `
|
|
107
|
+
SELECT * FROM __mj.vwOrders
|
|
108
|
+
WHERE Total > ANY (SELECT AVG(Total) FROM __mj.vwOrders GROUP BY CustomerID)
|
|
109
|
+
`;
|
|
110
|
+
const r = validator.validate(sql, ctx);
|
|
111
|
+
expect(r.valid).toBe(true);
|
|
112
|
+
});
|
|
113
|
+
it('should accept WHERE x = ALL(...)', () => {
|
|
114
|
+
const sql = `
|
|
115
|
+
SELECT * FROM __mj.vwProducts
|
|
116
|
+
WHERE Price >= ALL (SELECT MIN(Price) FROM __mj.vwProducts GROUP BY CategoryID)
|
|
117
|
+
`;
|
|
118
|
+
const r = validator.validate(sql, ctx);
|
|
119
|
+
expect(r.valid).toBe(true);
|
|
120
|
+
});
|
|
121
|
+
it('should accept IIF function (uses IF keyword internally)', () => {
|
|
122
|
+
const sql = `SELECT IIF(Status = 'Active', 1, 0) AS IsActive FROM __mj.vwUsers`;
|
|
123
|
+
const r = validator.validate(sql, ctx);
|
|
124
|
+
expect(r.valid).toBe(true);
|
|
125
|
+
});
|
|
126
|
+
it('should accept queries with NULLIF, COALESCE, ISNULL', () => {
|
|
127
|
+
const sql = `SELECT COALESCE(FirstName, 'Unknown'), ISNULL(LastName, ''), NULLIF(Status, '') FROM __mj.vwUsers`;
|
|
128
|
+
const r = validator.validate(sql, ctx);
|
|
129
|
+
expect(r.valid).toBe(true);
|
|
130
|
+
});
|
|
131
|
+
it('should accept CASE WHEN expressions', () => {
|
|
132
|
+
const sql = `
|
|
133
|
+
SELECT Name,
|
|
134
|
+
CASE WHEN Status = 'Active' THEN 'Yes' ELSE 'No' END AS IsActive
|
|
135
|
+
FROM __mj.vwUsers
|
|
136
|
+
`;
|
|
137
|
+
const r = validator.validate(sql, ctx);
|
|
138
|
+
expect(r.valid).toBe(true);
|
|
139
|
+
});
|
|
140
|
+
});
|
|
141
|
+
describe('rejected queries', () => {
|
|
142
|
+
it('should reject INSERT statement', () => {
|
|
143
|
+
const r = validator.validate("INSERT INTO Users (Name) VALUES ('test')", ctx);
|
|
144
|
+
expect(r.valid).toBe(false);
|
|
145
|
+
expect(r.trigger).toBe('INSERT');
|
|
146
|
+
});
|
|
147
|
+
it('should reject UPDATE statement', () => {
|
|
148
|
+
const r = validator.validate("UPDATE Users SET Name = 'test'", ctx);
|
|
149
|
+
expect(r.valid).toBe(false);
|
|
150
|
+
expect(r.trigger).toBe('UPDATE');
|
|
151
|
+
});
|
|
152
|
+
it('should reject DELETE statement', () => {
|
|
153
|
+
const r = validator.validate('DELETE FROM Users WHERE ID = 1', ctx);
|
|
154
|
+
expect(r.valid).toBe(false);
|
|
155
|
+
expect(r.trigger).toBe('DELETE');
|
|
156
|
+
});
|
|
157
|
+
it('should reject DROP TABLE', () => {
|
|
158
|
+
const r = validator.validate('DROP TABLE Users', ctx);
|
|
159
|
+
expect(r.valid).toBe(false);
|
|
160
|
+
expect(r.trigger).toBe('DROP');
|
|
161
|
+
});
|
|
162
|
+
it('should reject TRUNCATE', () => {
|
|
163
|
+
const r = validator.validate('TRUNCATE TABLE Users', ctx);
|
|
164
|
+
expect(r.valid).toBe(false);
|
|
165
|
+
expect(r.trigger).toBe('TRUNCATE');
|
|
166
|
+
});
|
|
167
|
+
it('should reject EXEC', () => {
|
|
168
|
+
const r = validator.validate('EXEC sp_help', ctx);
|
|
169
|
+
expect(r.valid).toBe(false);
|
|
170
|
+
expect(r.trigger).toBe('EXEC');
|
|
171
|
+
});
|
|
172
|
+
it('should reject EXECUTE', () => {
|
|
173
|
+
const r = validator.validate("EXECUTE sp_executesql N'SELECT 1'", ctx);
|
|
174
|
+
expect(r.valid).toBe(false);
|
|
175
|
+
expect(r.trigger).toBe('EXECUTE');
|
|
176
|
+
});
|
|
177
|
+
it('should reject statements with semicolons', () => {
|
|
178
|
+
const r = validator.validate('SELECT 1; DROP TABLE Users', ctx);
|
|
179
|
+
expect(r.valid).toBe(false);
|
|
180
|
+
// DROP is detected before semicolon in the keyword scan
|
|
181
|
+
expect(r.trigger).toBe('DROP');
|
|
182
|
+
});
|
|
183
|
+
it('should reject query not starting with SELECT or WITH', () => {
|
|
184
|
+
const r = validator.validate('CREATE TABLE Foo (ID INT)', ctx);
|
|
185
|
+
expect(r.valid).toBe(false);
|
|
186
|
+
});
|
|
187
|
+
it('should reject WAITFOR DELAY', () => {
|
|
188
|
+
const r = validator.validate("WAITFOR DELAY '00:00:05'", ctx);
|
|
189
|
+
expect(r.valid).toBe(false);
|
|
190
|
+
expect(r.trigger).toBe('WAITFOR');
|
|
191
|
+
});
|
|
192
|
+
it('should reject OPENROWSET', () => {
|
|
193
|
+
const r = validator.validate("SELECT * FROM OPENROWSET('SQLNCLI', 'Server=hack;')", ctx);
|
|
194
|
+
expect(r.valid).toBe(false);
|
|
195
|
+
expect(r.trigger).toBe('OPENROWSET');
|
|
196
|
+
});
|
|
197
|
+
it('should reject GRANT', () => {
|
|
198
|
+
const r = validator.validate('GRANT SELECT ON Users TO public', ctx);
|
|
199
|
+
expect(r.valid).toBe(false);
|
|
200
|
+
expect(r.trigger).toBe('GRANT');
|
|
201
|
+
});
|
|
202
|
+
it('should reject SHUTDOWN', () => {
|
|
203
|
+
const r = validator.validate('SHUTDOWN', ctx);
|
|
204
|
+
expect(r.valid).toBe(false);
|
|
205
|
+
expect(r.trigger).toBe('SHUTDOWN');
|
|
206
|
+
});
|
|
207
|
+
});
|
|
208
|
+
});
|
|
209
|
+
// ---------------------------------------------------------------
|
|
210
|
+
// validateFullQuery convenience method
|
|
211
|
+
// ---------------------------------------------------------------
|
|
212
|
+
describe('validateFullQuery', () => {
|
|
213
|
+
it('should pass valid SELECT', () => {
|
|
214
|
+
const r = validator.validateFullQuery('SELECT 1 AS One');
|
|
215
|
+
expect(r.valid).toBe(true);
|
|
216
|
+
});
|
|
217
|
+
it('should pass valid CTE', () => {
|
|
218
|
+
const r = validator.validateFullQuery('WITH cte AS (SELECT 1) SELECT * FROM cte');
|
|
219
|
+
expect(r.valid).toBe(true);
|
|
220
|
+
});
|
|
221
|
+
it('should fail on mutation', () => {
|
|
222
|
+
const r = validator.validateFullQuery("DELETE FROM Users");
|
|
223
|
+
expect(r.valid).toBe(false);
|
|
224
|
+
});
|
|
225
|
+
it('should fail on empty string', () => {
|
|
226
|
+
const r = validator.validateFullQuery('');
|
|
227
|
+
expect(r.valid).toBe(false);
|
|
228
|
+
});
|
|
229
|
+
it('should normalize literal \\n sequences and pass SQL with comment header', () => {
|
|
230
|
+
// Agent-generated SQL arrives with literal \n instead of real newlines
|
|
231
|
+
const sql = '-- Header Comment\\nSELECT TOP 10 * FROM Users\\nWHERE Status = \'Active\'';
|
|
232
|
+
const r = validator.validateFullQuery(sql);
|
|
233
|
+
expect(r.valid).toBe(true);
|
|
234
|
+
});
|
|
235
|
+
it('should normalize literal \\r\\n sequences', () => {
|
|
236
|
+
const sql = '-- Header\\r\\nSELECT 1 AS One';
|
|
237
|
+
const r = validator.validateFullQuery(sql);
|
|
238
|
+
expect(r.valid).toBe(true);
|
|
239
|
+
});
|
|
240
|
+
it('should still reject dangerous queries after normalization', () => {
|
|
241
|
+
const sql = '-- Innocent header\\nDELETE FROM Users';
|
|
242
|
+
const r = validator.validateFullQuery(sql);
|
|
243
|
+
expect(r.valid).toBe(false);
|
|
244
|
+
});
|
|
245
|
+
});
|
|
246
|
+
// ---------------------------------------------------------------
|
|
247
|
+
// Existing contexts (where_clause, aggregate, etc.)
|
|
248
|
+
// ---------------------------------------------------------------
|
|
249
|
+
describe('where_clause context', () => {
|
|
250
|
+
it('should accept simple field comparison', () => {
|
|
251
|
+
const r = validator.validate("Status = 'Active'", { context: 'where_clause' });
|
|
252
|
+
expect(r.valid).toBe(true);
|
|
253
|
+
});
|
|
254
|
+
it('should accept LIKE expression', () => {
|
|
255
|
+
const r = validator.validate("Name LIKE '%test%'", { context: 'where_clause' });
|
|
256
|
+
expect(r.valid).toBe(true);
|
|
257
|
+
});
|
|
258
|
+
it('should accept BETWEEN', () => {
|
|
259
|
+
const r = validator.validate("Age BETWEEN 18 AND 65", { context: 'where_clause' });
|
|
260
|
+
expect(r.valid).toBe(true);
|
|
261
|
+
});
|
|
262
|
+
it('should reject SELECT (subquery) by default', () => {
|
|
263
|
+
const r = validator.validate("ID IN (SELECT ID FROM Users)", { context: 'where_clause' });
|
|
264
|
+
expect(r.valid).toBe(false);
|
|
265
|
+
expect(r.trigger).toBe('SELECT');
|
|
266
|
+
});
|
|
267
|
+
it('should allow SELECT when allowSubqueries is true', () => {
|
|
268
|
+
const r = validator.validate("ID IN (SELECT ID FROM Users)", { context: 'where_clause', allowSubqueries: true });
|
|
269
|
+
expect(r.valid).toBe(true);
|
|
270
|
+
});
|
|
271
|
+
it('should reject comments', () => {
|
|
272
|
+
const r = validator.validate("Status = 'Active' -- comment", { context: 'where_clause' });
|
|
273
|
+
expect(r.valid).toBe(false);
|
|
274
|
+
expect(r.trigger).toBe('comment');
|
|
275
|
+
});
|
|
276
|
+
it('should reject semicolons', () => {
|
|
277
|
+
const r = validator.validate("1=1; DROP TABLE Users", { context: 'where_clause' });
|
|
278
|
+
expect(r.valid).toBe(false);
|
|
279
|
+
// DROP is detected before semicolon in the keyword scan
|
|
280
|
+
expect(r.trigger).toBe('DROP');
|
|
281
|
+
});
|
|
282
|
+
});
|
|
283
|
+
describe('aggregate context', () => {
|
|
284
|
+
it('should accept COUNT expression', () => {
|
|
285
|
+
const r = validator.validate('COUNT(ID)', { context: 'aggregate' });
|
|
286
|
+
expect(r.valid).toBe(true);
|
|
287
|
+
});
|
|
288
|
+
it('should accept SUM expression', () => {
|
|
289
|
+
const r = validator.validate('SUM(OrderTotal)', { context: 'aggregate' });
|
|
290
|
+
expect(r.valid).toBe(true);
|
|
291
|
+
});
|
|
292
|
+
it('should reject non-aggregate expression', () => {
|
|
293
|
+
const r = validator.validate('FieldName', { context: 'aggregate' });
|
|
294
|
+
expect(r.valid).toBe(false);
|
|
295
|
+
expect(r.error).toContain('aggregate function');
|
|
296
|
+
});
|
|
297
|
+
it('should allow non-aggregate when requireAggregate is false', () => {
|
|
298
|
+
const r = validator.validate('FieldName', { context: 'aggregate', requireAggregate: false });
|
|
299
|
+
expect(r.valid).toBe(true);
|
|
300
|
+
});
|
|
301
|
+
});
|
|
302
|
+
describe('order_by context', () => {
|
|
303
|
+
it('should accept simple field name', () => {
|
|
304
|
+
const r = validator.validate('Name ASC', { context: 'order_by' });
|
|
305
|
+
expect(r.valid).toBe(true);
|
|
306
|
+
});
|
|
307
|
+
it('should accept DESC ordering', () => {
|
|
308
|
+
const r = validator.validate('CreatedAt DESC', { context: 'order_by' });
|
|
309
|
+
expect(r.valid).toBe(true);
|
|
310
|
+
});
|
|
311
|
+
});
|
|
312
|
+
// ---------------------------------------------------------------
|
|
313
|
+
// String literal handling (false positive prevention)
|
|
314
|
+
// ---------------------------------------------------------------
|
|
315
|
+
describe('string literal handling', () => {
|
|
316
|
+
it('should not flag keywords inside string literals', () => {
|
|
317
|
+
const r = validator.validate("SELECT * FROM __mj.vwUsers WHERE Description = 'This will DROP the ball'", { context: 'full_query' });
|
|
318
|
+
// The word DROP is inside a string literal, so it should be stripped before checking
|
|
319
|
+
expect(r.valid).toBe(true);
|
|
320
|
+
});
|
|
321
|
+
it('should not flag INSERT inside a string literal', () => {
|
|
322
|
+
const r = validator.validate("SELECT * FROM __mj.vwLogs WHERE Message = 'INSERT completed successfully'", { context: 'full_query' });
|
|
323
|
+
expect(r.valid).toBe(true);
|
|
324
|
+
});
|
|
325
|
+
});
|
|
326
|
+
// ---------------------------------------------------------------
|
|
327
|
+
// Constants exports
|
|
328
|
+
// ---------------------------------------------------------------
|
|
329
|
+
describe('exported constants', () => {
|
|
330
|
+
it('DANGEROUS_SQL_KEYWORDS should include key mutation keywords', () => {
|
|
331
|
+
expect(DANGEROUS_SQL_KEYWORDS).toContain('INSERT');
|
|
332
|
+
expect(DANGEROUS_SQL_KEYWORDS).toContain('UPDATE');
|
|
333
|
+
expect(DANGEROUS_SQL_KEYWORDS).toContain('DELETE');
|
|
334
|
+
expect(DANGEROUS_SQL_KEYWORDS).toContain('DROP');
|
|
335
|
+
expect(DANGEROUS_SQL_KEYWORDS).toContain('EXEC');
|
|
336
|
+
});
|
|
337
|
+
it('FULL_QUERY_ALLOWED_KEYWORDS should include set operations', () => {
|
|
338
|
+
expect(FULL_QUERY_ALLOWED_KEYWORDS).toContain('UNION');
|
|
339
|
+
expect(FULL_QUERY_ALLOWED_KEYWORDS).toContain('EXISTS');
|
|
340
|
+
expect(FULL_QUERY_ALLOWED_KEYWORDS).toContain('ANY');
|
|
341
|
+
expect(FULL_QUERY_ALLOWED_KEYWORDS).toContain('ALL');
|
|
342
|
+
});
|
|
343
|
+
it('ALLOWED_SQL_FUNCTIONS should include aggregate functions', () => {
|
|
344
|
+
expect(ALLOWED_SQL_FUNCTIONS.aggregates).toContain('COUNT');
|
|
345
|
+
expect(ALLOWED_SQL_FUNCTIONS.aggregates).toContain('SUM');
|
|
346
|
+
expect(ALLOWED_SQL_FUNCTIONS.aggregates).toContain('AVG');
|
|
347
|
+
});
|
|
348
|
+
});
|
|
349
|
+
});
|
|
350
|
+
//# sourceMappingURL=SQLExpressionValidator.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SQLExpressionValidator.test.js","sourceRoot":"","sources":["../../src/__tests__/SQLExpressionValidator.test.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED