@memberjunction/global 6.1.4 → 6.1.6

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.
@@ -10,6 +10,7 @@
10
10
  * @module @memberjunction/global/SQLExpressionValidator
11
11
  */
12
12
  import { BaseSingleton } from './BaseSingleton.js';
13
+ import { SQLScreeningDialect } from './SQLScreeningScanner.js';
13
14
  /**
14
15
  * Dangerous SQL keywords that are never allowed in user-provided expressions
15
16
  */
@@ -26,34 +27,30 @@ export declare const FULL_QUERY_ALLOWED_KEYWORDS: readonly ["EXISTS", "ANY", "AL
26
27
  * a schema-enumeration and credential-exfiltration primitive
27
28
  * (e.g. `SELECT name, password_hash FROM sys.sql_logins`,
28
29
  * `SELECT * FROM INFORMATION_SCHEMA.COLUMNS`, `SELECT * FROM pg_catalog.pg_authid`).
29
- * String literals are stripped before this check runs, so a literal value like `'sys.x'` is safe.
30
+ * The check reads {@link SQLScreeningScan.CodeWithIdentifiers}: string literals are removed, so a
31
+ * literal value like `'sys.x'` is safe, and quoted names are unwrapped, so `[sys].[x]` is caught.
30
32
  */
31
33
  export declare const BLOCKED_SYSTEM_OBJECT_PATTERNS: RegExp[];
32
34
  /**
33
- * Removes SQL string literals from a clause or expression so that a keyword denylist can be
34
- * applied to the *code* portion without tripping over keywords that appear inside quoted data
35
- * (e.g. `Comments LIKE '%--%'`).
35
+ * Replaces each SQL string literal with one space so that a keyword denylist can be applied to the
36
+ * rest without tripping over keywords inside quoted data (e.g. `Comments LIKE '%--%'`). Quoted
37
+ * identifiers and comments are left as written.
36
38
  *
37
- * 🚨 SECURITY — this is the single implementation of literal-stripping for MJ's SQL screens, and
38
- * it MUST stay byte-for-byte consistent with how the database parses literals. If the stripper
39
- * removes a span the database does NOT treat as a literal, everything hidden inside that span
40
- * bypasses the denylist while the database still executes it.
41
- *
42
- * An earlier version of this logic (duplicated in two places, which is how it survived) honored
43
- * **backslash escaping** — `/(['"])(?:(?=(\\?))\2[\s\S])*?\1/g`. SQL Server and PostgreSQL do not
44
- * treat `\` as an escape character, so `x = 'a\') ; DROP TABLE Users; --'` was swallowed whole as
45
- * one "literal" and stripped to `x = `, which passed every denylist — while the database closed
46
- * the literal at the real quote and executed the stacked statement.
47
- *
48
- * **Do NOT reintroduce backslash-escape handling here, and do NOT inline a second copy of this
49
- * regex anywhere else — call this function.**
39
+ * 🚨 SECURITY — literals are found by {@link ScanSQLForScreening}, which reads the text the way the
40
+ * database does: a quote inside a T-SQL `[…]` identifier, a comment or a PostgreSQL `$$…$$` string
41
+ * opens no literal, and a backslash escapes a quote only inside a PostgreSQL `E'…'` string. A
42
+ * stripper that removes a span the database does NOT treat as a literal hides everything inside it
43
+ * from the denylist while the database still runs it. Screens should call
44
+ * {@link ScanSQLForScreening} directly, which also reports comments and text it cannot classify.
50
45
  *
51
46
  * @param sql The clause, expression, or query to strip literals from
52
- * @returns The input with every complete string literal removed. An UNTERMINATED literal is left
53
- * in place on purpose: the stray quote and everything after it stay visible to the
54
- * denylist rather than being silently swallowed.
47
+ * @param dialect The dialect that will run the SQL. Without one, the text must read the same way
48
+ * under every dialect the scanner knows.
49
+ * @returns The input with each string literal replaced by a space. The input is returned unchanged
50
+ * when it cannot be classified (for example an unterminated literal) or when the dialects
51
+ * disagree on where its literals are, so a denylist still sees all of it.
55
52
  */
56
- export declare function StripSQLStringLiterals(sql: string): string;
53
+ export declare function StripSQLStringLiterals(sql: string, dialect?: SQLScreeningDialect): string;
57
54
  /**
58
55
  * Safe SQL functions allowed in expressions, organized by category
59
56
  */
@@ -101,6 +98,11 @@ export interface SQLValidationOptions {
101
98
  additionalAllowed?: string[];
102
99
  /** Custom blocked keywords to add */
103
100
  additionalBlocked?: string[];
101
+ /**
102
+ * The dialect that will run the SQL, which decides how quotes, identifiers and comments are read.
103
+ * Without one, the SQL must pass under every dialect {@link ScanSQLForScreening} knows.
104
+ */
105
+ Dialect?: SQLScreeningDialect;
104
106
  }
105
107
  /**
106
108
  * Central SQL expression validator for preventing SQL injection.
@@ -141,16 +143,20 @@ export declare class SQLExpressionValidator extends BaseSingleton<SQLExpressionV
141
143
  */
142
144
  validate(expression: string, options: SQLValidationOptions): SQLValidationResult;
143
145
  /**
144
- * Remove string literals to avoid false positives in keyword detection.
146
+ * Runs every check against one dialect's reading of the expression.
145
147
  *
146
- * 🚨 SECURITY: delegates to {@link StripSQLStringLiterals} — read the warning there before
147
- * changing anything about how literals are matched. This must never grow its own regex again.
148
+ * 🚨 SECURITY: the checks read the scanner's projections, never the raw text. Do not add a regex
149
+ * that finds literals, identifiers or comments here; see {@link ScanSQLForScreening}.
148
150
  */
149
- private removeStringLiterals;
151
+ private validateReading;
150
152
  /**
151
153
  * Check for dangerous SQL patterns that indicate injection attempts
152
154
  */
153
155
  private checkDangerousPatterns;
156
+ /**
157
+ * The keywords {@link checkDangerousPatterns} rejects in this context.
158
+ */
159
+ private blockedKeywords;
154
160
  /**
155
161
  * Check that function names are in the allowlist
156
162
  */
@@ -163,12 +169,6 @@ export declare class SQLExpressionValidator extends BaseSingleton<SQLExpressionV
163
169
  * Validate field references exist in entity (lenient mode - just for logging)
164
170
  */
165
171
  private checkFieldReferences;
166
- /**
167
- * Strip SQL comments (single-line -- and multi-line block comments) from a query.
168
- * Used by full_query context to allow agent-generated header comments
169
- * without triggering the comment injection check.
170
- */
171
- private stripSQLComments;
172
172
  /**
173
173
  * Escape special regex characters in a string
174
174
  */
@@ -186,7 +186,11 @@ export declare class SQLExpressionValidator extends BaseSingleton<SQLExpressionV
186
186
  * Validate a full SQL query (SELECT or WITH/CTE statement).
187
187
  * Blocks mutations, dangerous operations, and multi-statement injection.
188
188
  * Allows SELECT, subqueries, set operations, and SQL comments.
189
+ *
190
+ * @param sql The query to validate
191
+ * @param dialect The dialect that will run the query. Without one, the query must pass under
192
+ * every dialect {@link ScanSQLForScreening} knows.
189
193
  */
190
- validateFullQuery(sql: string): SQLValidationResult;
194
+ validateFullQuery(sql: string, dialect?: SQLScreeningDialect): SQLValidationResult;
191
195
  }
192
196
  //# sourceMappingURL=SQLExpressionValidator.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"SQLExpressionValidator.d.ts","sourceRoot":"","sources":["../src/SQLExpressionValidator.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAEhD;;GAEG;AACH,eAAO,MAAM,sBAAsB,2gBA0CzB,CAAC;AAEX;;;GAGG;AACH,eAAO,MAAM,2BAA2B,wFAe9B,CAAC;AAEX;;;;;;;;GAQG;AACH,eAAO,MAAM,8BAA8B,EAAE,MAAM,EAMlD,CAAC;AAcF;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAE1D;AAED;;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,sBAAuB,SAAQ,aAAa,CAAC,sBAAsB,CAAC;IAC/E;;OAEG;;IAKH;;OAEG;IACH,WAAkB,QAAQ,IAAI,sBAAsB,CAEnD;IAED;;;;;;OAMG;IACI,QAAQ,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,oBAAoB,GAAG,mBAAmB;IAoCvF;;;;;OAKG;IACH,OAAO,CAAC,oBAAoB;IAI5B;;OAEG;IACH,OAAO,CAAC,sBAAsB;IAkF9B;;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
+ {"version":3,"file":"SQLExpressionValidator.d.ts","sourceRoot":"","sources":["../src/SQLExpressionValidator.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EAGL,mBAAmB,EAGpB,MAAM,uBAAuB,CAAC;AAE/B;;GAEG;AACH,eAAO,MAAM,sBAAsB,2gBA0CzB,CAAC;AAEX;;;GAGG;AACH,eAAO,MAAM,2BAA2B,wFAe9B,CAAC;AAEX;;;;;;;;;GASG;AACH,eAAO,MAAM,8BAA8B,EAAE,MAAM,EAMlD,CAAC;AAQF;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,mBAAmB,GAAG,MAAM,CAKzF;AAcD;;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;IAE7B;;;OAGG;IACH,OAAO,CAAC,EAAE,mBAAmB,CAAC;CAC/B;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,qBAAa,sBAAuB,SAAQ,aAAa,CAAC,sBAAsB,CAAC;IAC/E;;OAEG;;IAKH;;OAEG;IACH,WAAkB,QAAQ,IAAI,sBAAsB,CAEnD;IAED;;;;;;OAMG;IACI,QAAQ,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,oBAAoB,GAAG,mBAAmB;IAmBvF;;;;;OAKG;IACH,OAAO,CAAC,eAAe;IA8BvB;;OAEG;IACH,OAAO,CAAC,sBAAsB;IA0D9B;;OAEG;IACH,OAAO,CAAC,eAAe;IAsBvB;;OAEG;IACH,OAAO,CAAC,kBAAkB;IA2B1B;;OAEG;IACH,OAAO,CAAC,iBAAiB;IA+BzB;;OAEG;IACH,OAAO,CAAC,oBAAoB;IA4B5B;;OAEG;IACH,OAAO,CAAC,WAAW;IAInB;;;;;;;OAOG;IACH,OAAO,CAAC,sBAAsB;IAQ9B;;;;;;;;OAQG;IACI,iBAAiB,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,mBAAmB,GAAG,mBAAmB;CAO1F"}
@@ -10,6 +10,7 @@
10
10
  * @module @memberjunction/global/SQLExpressionValidator
11
11
  */
12
12
  import { BaseSingleton } from './BaseSingleton.js';
13
+ import { ScanSQLForScreening, SQL_SCREENING_DIALECTS, } from './SQLScreeningScanner.js';
13
14
  /**
14
15
  * Dangerous SQL keywords that are never allowed in user-provided expressions
15
16
  */
@@ -67,7 +68,8 @@ export const FULL_QUERY_ALLOWED_KEYWORDS = [
67
68
  * a schema-enumeration and credential-exfiltration primitive
68
69
  * (e.g. `SELECT name, password_hash FROM sys.sql_logins`,
69
70
  * `SELECT * FROM INFORMATION_SCHEMA.COLUMNS`, `SELECT * FROM pg_catalog.pg_authid`).
70
- * String literals are stripped before this check runs, so a literal value like `'sys.x'` is safe.
71
+ * The check reads {@link SQLScreeningScan.CodeWithIdentifiers}: string literals are removed, so a
72
+ * literal value like `'sys.x'` is safe, and quoted names are unwrapped, so `[sys].[x]` is caught.
71
73
  */
72
74
  export const BLOCKED_SYSTEM_OBJECT_PATTERNS = [
73
75
  /\bSYS\s*\.\s*\w/i, // SQL Server system catalog schema: sys.sql_logins, sys.objects, sys.fn_*, ...
@@ -77,42 +79,47 @@ export const BLOCKED_SYSTEM_OBJECT_PATTERNS = [
77
79
  /\bPG_(AUTHID|SHADOW|USER|ROLES)\b/i, // PostgreSQL credential / role catalogs
78
80
  ];
79
81
  /**
80
- * Matches SQL string literals the way SQL Server and PostgreSQL (with the default
81
- * `standard_conforming_strings=on`) actually parse them: a literal is closed by the next
82
- * single quote, `''` is an embedded quote, and a backslash is an ORDINARY character that
83
- * does NOT escape the closing quote. Double-quoted runs are matched with the same doubling
84
- * rule so a delimited identifier can't hide a payload either.
85
- *
86
- * @see StripSQLStringLiterals — use that, not this constant, so every caller gets the
87
- * documented semantics and the two validators in MJ can never drift apart again.
82
+ * The keywords a full query may open with. Without the `u` flag, the `i` flag matches ASCII letters
83
+ * only, so no other letter is case-mapped to S, E, L, C, T, W, I or H.
88
84
  */
89
- const SQL_STRING_LITERAL_PATTERN = /'(?:[^']|'')*'|"(?:[^"]|"")*"/g;
85
+ const FULL_QUERY_OPENING_KEYWORD = /^(?:SELECT|WITH)$/i;
90
86
  /**
91
- * Removes SQL string literals from a clause or expression so that a keyword denylist can be
92
- * applied to the *code* portion without tripping over keywords that appear inside quoted data
93
- * (e.g. `Comments LIKE '%--%'`).
94
- *
95
- * 🚨 SECURITY — this is the single implementation of literal-stripping for MJ's SQL screens, and
96
- * it MUST stay byte-for-byte consistent with how the database parses literals. If the stripper
97
- * removes a span the database does NOT treat as a literal, everything hidden inside that span
98
- * bypasses the denylist while the database still executes it.
99
- *
100
- * An earlier version of this logic (duplicated in two places, which is how it survived) honored
101
- * **backslash escaping** — `/(['"])(?:(?=(\\?))\2[\s\S])*?\1/g`. SQL Server and PostgreSQL do not
102
- * treat `\` as an escape character, so `x = 'a\') ; DROP TABLE Users; --'` was swallowed whole as
103
- * one "literal" and stripped to `x = `, which passed every denylist — while the database closed
104
- * the literal at the real quote and executed the stacked statement.
87
+ * Replaces each SQL string literal with one space so that a keyword denylist can be applied to the
88
+ * rest without tripping over keywords inside quoted data (e.g. `Comments LIKE '%--%'`). Quoted
89
+ * identifiers and comments are left as written.
105
90
  *
106
- * **Do NOT reintroduce backslash-escape handling here, and do NOT inline a second copy of this
107
- * regex anywhere else — call this function.**
91
+ * 🚨 SECURITY — literals are found by {@link ScanSQLForScreening}, which reads the text the way the
92
+ * database does: a quote inside a T-SQL `[…]` identifier, a comment or a PostgreSQL `$$…$$` string
93
+ * opens no literal, and a backslash escapes a quote only inside a PostgreSQL `E'…'` string. A
94
+ * stripper that removes a span the database does NOT treat as a literal hides everything inside it
95
+ * from the denylist while the database still runs it. Screens should call
96
+ * {@link ScanSQLForScreening} directly, which also reports comments and text it cannot classify.
108
97
  *
109
98
  * @param sql The clause, expression, or query to strip literals from
110
- * @returns The input with every complete string literal removed. An UNTERMINATED literal is left
111
- * in place on purpose: the stray quote and everything after it stay visible to the
112
- * denylist rather than being silently swallowed.
99
+ * @param dialect The dialect that will run the SQL. Without one, the text must read the same way
100
+ * under every dialect the scanner knows.
101
+ * @returns The input with each string literal replaced by a space. The input is returned unchanged
102
+ * when it cannot be classified (for example an unterminated literal) or when the dialects
103
+ * disagree on where its literals are, so a denylist still sees all of it.
113
104
  */
114
- export function StripSQLStringLiterals(sql) {
115
- return sql.replace(SQL_STRING_LITERAL_PATTERN, '');
105
+ export function StripSQLStringLiterals(sql, dialect) {
106
+ const scans = (dialect ? [dialect] : SQL_SCREENING_DIALECTS).map(d => ScanSQLForScreening(sql, d));
107
+ if (scans.some(scan => !scan.Classified))
108
+ return sql;
109
+ const readings = scans.map(scan => replaceStringSpans(sql, scan.Spans));
110
+ return readings.every(reading => reading === readings[0]) ? readings[0] : sql;
111
+ }
112
+ /** Writes `sql` with each string span replaced by one space. */
113
+ function replaceStringSpans(sql, spans) {
114
+ let result = '';
115
+ let from = 0;
116
+ for (const span of spans) {
117
+ if (span.Kind !== 'string')
118
+ continue;
119
+ result += sql.slice(from, span.Start) + ' ';
120
+ from = span.End;
121
+ }
122
+ return result + sql.slice(from);
116
123
  }
117
124
  /**
118
125
  * Safe SQL functions allowed in expressions, organized by category
@@ -186,75 +193,65 @@ export class SQLExpressionValidator extends BaseSingleton {
186
193
  if (!trimmed) {
187
194
  return { valid: false, error: 'Expression cannot be empty' };
188
195
  }
189
- // Step 1: Remove string literals to avoid false positives
190
- const withoutStrings = this.removeStringLiterals(trimmed);
191
- // Step 2: Check for dangerous patterns
192
- const dangerCheck = this.checkDangerousPatterns(withoutStrings, options);
196
+ // Read the text the way the database will. When the dialect is unknown, every reading must pass.
197
+ const dialects = options.Dialect ? [options.Dialect] : SQL_SCREENING_DIALECTS;
198
+ for (const dialect of dialects) {
199
+ const result = this.validateReading(ScanSQLForScreening(trimmed, dialect), options);
200
+ if (!result.valid)
201
+ return result;
202
+ }
203
+ return { valid: true };
204
+ }
205
+ /**
206
+ * Runs every check against one dialect's reading of the expression.
207
+ *
208
+ * 🚨 SECURITY: the checks read the scanner's projections, never the raw text. Do not add a regex
209
+ * that finds literals, identifiers or comments here; see {@link ScanSQLForScreening}.
210
+ */
211
+ validateReading(scan, options) {
212
+ if (!scan.Classified) {
213
+ return {
214
+ valid: false,
215
+ error: `SQL could not be read safely as ${scan.Dialect}: ${scan.Error}`,
216
+ trigger: 'unclassified'
217
+ };
218
+ }
219
+ const dangerCheck = this.checkDangerousPatterns(scan, options);
193
220
  if (!dangerCheck.valid)
194
221
  return dangerCheck;
195
- // Step 3: Validate function names are in allowlist (skip for full queries —
196
- // the function allowlist is designed for expression fragments, not full SQL statements)
222
+ // The function allowlist is designed for expression fragments, not full SQL statements.
223
+ // Quoted names are unwrapped, so a quoted function call is checked too.
197
224
  if (options.context !== 'full_query') {
198
- const functionCheck = this.checkFunctionNames(withoutStrings, options);
225
+ const functionCheck = this.checkFunctionNames(scan.CodeWithIdentifiers, options);
199
226
  if (!functionCheck.valid)
200
227
  return functionCheck;
201
228
  }
202
- // Step 4: Context-specific validation
203
- const contextCheck = this.checkContextRules(withoutStrings, options);
229
+ const contextCheck = this.checkContextRules(scan, options);
204
230
  if (!contextCheck.valid)
205
231
  return contextCheck;
206
- // Step 5: Optional field reference validation (lenient - just logs warnings)
232
+ // Optional field reference validation (lenient - just logs warnings)
207
233
  if (options.entityFields?.length) {
208
- this.checkFieldReferences(withoutStrings, options.entityFields);
234
+ this.checkFieldReferences(scan.Code, options.entityFields);
209
235
  }
210
236
  return { valid: true };
211
237
  }
212
- /**
213
- * Remove string literals to avoid false positives in keyword detection.
214
- *
215
- * 🚨 SECURITY: delegates to {@link StripSQLStringLiterals} — read the warning there before
216
- * changing anything about how literals are matched. This must never grow its own regex again.
217
- */
218
- removeStringLiterals(expression) {
219
- return StripSQLStringLiterals(expression);
220
- }
221
238
  /**
222
239
  * Check for dangerous SQL patterns that indicate injection attempts
223
240
  */
224
- checkDangerousPatterns(expression, options) {
241
+ checkDangerousPatterns(scan, options) {
225
242
  const isFullQuery = options.context === 'full_query';
226
- // Build blocked list - explicitly typed as string[] for mutability
227
- let blocked = [...DANGEROUS_SQL_KEYWORDS];
228
- if (options.additionalBlocked) {
229
- blocked.push(...options.additionalBlocked);
230
- }
231
- // For full_query context, remove keywords that are legitimate in SELECT statements
232
- if (isFullQuery) {
233
- const allowedSet = new Set(FULL_QUERY_ALLOWED_KEYWORDS.map(k => k.toUpperCase()));
234
- blocked = blocked.filter(kw => !allowedSet.has(kw.toUpperCase()));
235
- }
236
- // Add SELECT to blocked unless context allows it (prevents subqueries in expressions)
237
- if (!isFullQuery && !options.allowSubqueries && !blocked.includes('SELECT')) {
238
- blocked.push('SELECT');
239
- }
240
- // For full_query, strip comments before keyword checking (agent SQL has header comment blocks).
241
- // For expressions, comments are still rejected outright as injection vectors.
242
- let textToCheck;
243
- if (isFullQuery) {
244
- textToCheck = this.stripSQLComments(expression).toUpperCase();
245
- }
246
- else {
247
- const upper = expression.toUpperCase();
248
- if (upper.includes('--') || upper.includes('/*') || upper.includes('*/')) {
249
- return {
250
- valid: false,
251
- error: 'Comments are not allowed in SQL expressions',
252
- trigger: 'comment'
253
- };
254
- }
255
- textToCheck = upper;
243
+ const textToCheck = scan.Code.toUpperCase();
244
+ // Full queries may carry comments (agent SQL has header comment blocks); the scan has already
245
+ // blanked them. In expressions, comments are rejected outright as injection vectors, and so is
246
+ // a stray `*/`, which is code.
247
+ if (!isFullQuery && (scan.CommentCount > 0 || textToCheck.includes('*/'))) {
248
+ return {
249
+ valid: false,
250
+ error: 'Comments are not allowed in SQL expressions',
251
+ trigger: 'comment'
252
+ };
256
253
  }
257
- for (const keyword of blocked) {
254
+ for (const keyword of this.blockedKeywords(options)) {
258
255
  // Use word boundaries to avoid false positives (e.g., "DESCRIPTION" containing "EXEC")
259
256
  const pattern = new RegExp(`\\b${this.escapeRegex(keyword)}\\b`, 'i');
260
257
  if (pattern.test(textToCheck)) {
@@ -269,9 +266,10 @@ export class SQLExpressionValidator extends BaseSingleton {
269
266
  // Block references to database system catalogs / metadata objects in ALL contexts
270
267
  // (including full_query). These live outside MemberJunction's entity-permission model, so
271
268
  // permitting them turns a validated SELECT into a schema-enumeration / credential-exfiltration
272
- // primitive. String literals were already stripped upstream, so legitimate literal values are safe.
269
+ // primitive. Literals are blanked and quoted names unwrapped, so `[sys].[x]` is caught too.
270
+ const namesToCheck = scan.CodeWithIdentifiers.toUpperCase();
273
271
  for (const sysPattern of BLOCKED_SYSTEM_OBJECT_PATTERNS) {
274
- if (sysPattern.test(textToCheck)) {
272
+ if (sysPattern.test(namesToCheck)) {
275
273
  return {
276
274
  valid: false,
277
275
  error: 'Access to database system catalogs / metadata objects is not allowed',
@@ -279,13 +277,10 @@ export class SQLExpressionValidator extends BaseSingleton {
279
277
  };
280
278
  }
281
279
  }
282
- // Check statement terminator (prevents multi-statement injection).
283
- // For full_query context, strip comments first (a trailing semicolon may be followed by
284
- // an inline comment like `ORDER BY x DESC; -- highest first`), then strip the trailing
285
- // semicolon. Only reject if semicolons remain mid-statement, indicating injection.
286
- const textForSemicolonCheck = isFullQuery
287
- ? this.stripSQLComments(expression).replace(/;\s*$/, '') // strip comments then trailing semicolon
288
- : expression;
280
+ // Check statement terminator (prevents multi-statement injection). Comments are already
281
+ // blanked, so a full query may end with one semicolon even when a comment follows it
282
+ // (`ORDER BY x DESC; -- highest first`). A semicolon anywhere else indicates injection.
283
+ const textForSemicolonCheck = isFullQuery ? textToCheck.replace(/;\s*$/, '') : textToCheck;
289
284
  if (textForSemicolonCheck.includes(';')) {
290
285
  return {
291
286
  valid: false,
@@ -295,6 +290,27 @@ export class SQLExpressionValidator extends BaseSingleton {
295
290
  }
296
291
  return { valid: true };
297
292
  }
293
+ /**
294
+ * The keywords {@link checkDangerousPatterns} rejects in this context.
295
+ */
296
+ blockedKeywords(options) {
297
+ const isFullQuery = options.context === 'full_query';
298
+ // Build blocked list - explicitly typed as string[] for mutability
299
+ let blocked = [...DANGEROUS_SQL_KEYWORDS];
300
+ if (options.additionalBlocked) {
301
+ blocked.push(...options.additionalBlocked);
302
+ }
303
+ // For full_query context, remove keywords that are legitimate in SELECT statements
304
+ if (isFullQuery) {
305
+ const allowedSet = new Set(FULL_QUERY_ALLOWED_KEYWORDS.map(k => k.toUpperCase()));
306
+ blocked = blocked.filter(kw => !allowedSet.has(kw.toUpperCase()));
307
+ }
308
+ // Add SELECT to blocked unless context allows it (prevents subqueries in expressions)
309
+ if (!isFullQuery && !options.allowSubqueries && !blocked.includes('SELECT')) {
310
+ blocked.push('SELECT');
311
+ }
312
+ return blocked;
313
+ }
298
314
  /**
299
315
  * Check that function names are in the allowlist
300
316
  */
@@ -324,12 +340,12 @@ export class SQLExpressionValidator extends BaseSingleton {
324
340
  /**
325
341
  * Context-specific validation rules
326
342
  */
327
- checkContextRules(expression, options) {
343
+ checkContextRules(scan, options) {
328
344
  // For aggregate context, require at least one aggregate function (unless explicitly disabled)
329
345
  if (options.context === 'aggregate' && options.requireAggregate !== false) {
330
346
  const hasAggregate = ALLOWED_SQL_FUNCTIONS.aggregates.some(fn => {
331
347
  const pattern = new RegExp(`\\b${fn}\\s*\\(`, 'i');
332
- return pattern.test(expression);
348
+ return pattern.test(scan.Code);
333
349
  });
334
350
  if (!hasAggregate) {
335
351
  return {
@@ -339,17 +355,15 @@ export class SQLExpressionValidator extends BaseSingleton {
339
355
  };
340
356
  }
341
357
  }
342
- // For full_query context, the query must start with SELECT or WITH (CTE)
343
- if (options.context === 'full_query') {
344
- const stripped = this.stripSQLComments(expression).trim();
345
- const upper = stripped.toUpperCase();
346
- if (!upper.startsWith('SELECT') && !upper.startsWith('WITH')) {
347
- return {
348
- valid: false,
349
- error: 'Ad-hoc query must start with SELECT or WITH',
350
- suggestion: 'Only SELECT statements and CTEs (WITH ... AS) are allowed'
351
- };
352
- }
358
+ // For full_query context, the first token (after comments) must be the unquoted keyword SELECT or
359
+ // WITH, compared in ASCII. SQL Server runs a batch that opens with any other name, quoted or not,
360
+ // as a procedure call.
361
+ if (options.context === 'full_query' && !FULL_QUERY_OPENING_KEYWORD.test(scan.LeadingWord ?? '')) {
362
+ return {
363
+ valid: false,
364
+ error: 'Ad-hoc query must start with SELECT or WITH',
365
+ suggestion: 'Only SELECT statements and CTEs (WITH ... AS) are allowed'
366
+ };
353
367
  }
354
368
  return { valid: true };
355
369
  }
@@ -379,16 +393,6 @@ export class SQLExpressionValidator extends BaseSingleton {
379
393
  // For now, we allow it to pass
380
394
  }
381
395
  }
382
- /**
383
- * Strip SQL comments (single-line -- and multi-line block comments) from a query.
384
- * Used by full_query context to allow agent-generated header comments
385
- * without triggering the comment injection check.
386
- */
387
- stripSQLComments(sql) {
388
- return sql
389
- .replace(/--[^\n]*/g, '') // Single-line comments
390
- .replace(/\/\*[\s\S]*?\*\//g, ''); // Block comments
391
- }
392
396
  /**
393
397
  * Escape special regex characters in a string
394
398
  */
@@ -414,13 +418,17 @@ export class SQLExpressionValidator extends BaseSingleton {
414
418
  * Validate a full SQL query (SELECT or WITH/CTE statement).
415
419
  * Blocks mutations, dangerous operations, and multi-statement injection.
416
420
  * Allows SELECT, subqueries, set operations, and SQL comments.
421
+ *
422
+ * @param sql The query to validate
423
+ * @param dialect The dialect that will run the query. Without one, the query must pass under
424
+ * every dialect {@link ScanSQLForScreening} knows.
417
425
  */
418
- validateFullQuery(sql) {
426
+ validateFullQuery(sql, dialect) {
419
427
  // Normalize literal escape sequences before validation — agent-generated
420
428
  // SQL may arrive with literal \n instead of real newlines, which breaks
421
429
  // comment stripping and the "must start with SELECT" check.
422
430
  const normalized = this.normalizeSQLWhitespace(sql);
423
- return this.validate(normalized, { context: 'full_query' });
431
+ return this.validate(normalized, { context: 'full_query', Dialect: dialect });
424
432
  }
425
433
  }
426
434
  //# sourceMappingURL=SQLExpressionValidator.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"SQLExpressionValidator.js","sourceRoot":"","sources":["../src/SQLExpressionValidator.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"SQLExpressionValidator.js","sourceRoot":"","sources":["../src/SQLExpressionValidator.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,91 @@
1
+ /**
2
+ * @fileoverview Dialect-aware SQL scanner for MemberJunction's SQL denylist screens.
3
+ *
4
+ * A denylist screen is only as good as its idea of which text is code. This scanner reads SQL the
5
+ * way SQL Server or PostgreSQL splits it into tokens and marks every string literal, quoted
6
+ * identifier and comment, so a screen checks exactly the text the database runs as code. When it
7
+ * cannot read the text the way the database would, it reports that, so the screen rejects the text
8
+ * instead of guessing.
9
+ *
10
+ * Used by `SQLExpressionValidator` and `DatabaseProviderBase.ValidateUserProvidedSQLClause`.
11
+ *
12
+ * @module @memberjunction/global/SQLScreeningScanner
13
+ */
14
+ /** SQL dialects whose lexical rules {@link ScanSQLForScreening} knows. */
15
+ export type SQLScreeningDialect = 'sqlserver' | 'postgresql';
16
+ /**
17
+ * Every dialect {@link ScanSQLForScreening} knows. A screen that does not know which database will
18
+ * run the SQL must accept it under each one.
19
+ */
20
+ export declare const SQL_SCREENING_DIALECTS: readonly SQLScreeningDialect[];
21
+ /** Kinds of text that the database never runs as code. */
22
+ export type SQLScreeningSpanKind = 'string' | 'identifier' | 'comment';
23
+ /** One string literal, quoted identifier or comment found by {@link ScanSQLForScreening}. */
24
+ export interface SQLScreeningSpan {
25
+ Kind: SQLScreeningSpanKind;
26
+ /** Offset of the first character, including a prefix such as `N` or `E`. */
27
+ Start: number;
28
+ /** Offset just past the last character. */
29
+ End: number;
30
+ }
31
+ /** Result of {@link ScanSQLForScreening}. */
32
+ export interface SQLScreeningScan {
33
+ /** The dialect whose rules were applied. */
34
+ Dialect: SQLScreeningDialect;
35
+ /** True when every character was read the way the database reads it. When false, reject the text. */
36
+ Classified: boolean;
37
+ /** Why the text could not be classified; null when {@link Classified} is true. */
38
+ Error: string | null;
39
+ /** The string literals, quoted identifiers and comments found, in order. */
40
+ Spans: SQLScreeningSpan[];
41
+ /** Number of comments found. */
42
+ CommentCount: number;
43
+ /**
44
+ * The input with each string literal, quoted identifier and comment replaced by one space, and a
45
+ * space between a number and a word written against it. Only code remains, split where the
46
+ * database splits it, so `N'x'UNION` reads as ` UNION` and `1UNION` as `1 UNION`. Keyword,
47
+ * statement-separator and comment-marker checks read this. When {@link Classified} is false,
48
+ * the text from the point where the scan stopped is left as written.
49
+ */
50
+ Code: string;
51
+ /**
52
+ * {@link Code}, except each quoted identifier is written as its bare name between spaces, so
53
+ * `[sys].[objects]` reads as ` sys . objects `. Checks for object and function names read this,
54
+ * so quoting a name does not hide it.
55
+ */
56
+ CodeWithIdentifiers: string;
57
+ /**
58
+ * The first token that is not whitespace or a comment, when that token is an unquoted word and
59
+ * the character after it is ASCII, so every server ends the word in the same place. Null when a
60
+ * literal, quoted identifier, number or symbol comes first, or there is no token. Checks for the
61
+ * statement's opening keyword read this.
62
+ */
63
+ LeadingWord: string | null;
64
+ }
65
+ /**
66
+ * Reads `sql` the way `dialect` splits it into tokens. Returns the string literals, quoted
67
+ * identifiers and comments it contains, and the code that remains.
68
+ *
69
+ * Both dialects: `'…'` and `N'…'` strings, in which `''` is an escaped quote and a backslash is an
70
+ * ordinary character; `"…"` identifiers with `""` escapes; `--` comments to the end of the line; and
71
+ * nested block comments. SQL Server adds `[…]` identifiers with `]]` escapes. PostgreSQL adds `E'…'`
72
+ * strings, in which a backslash escapes the next character, and dollar-quoted strings (`$$…$$`,
73
+ * `$tag$…$tag$`); a `[` is code there.
74
+ *
75
+ * 🚨 Do not add backslash escapes to plain `'…'` strings. Neither server honors them (PostgreSQL is
76
+ * assumed to run with `standard_conforming_strings = on`, its default since 9.1), and a scanner that
77
+ * does reads `x = 'a\') ; DROP TABLE t; --'` as one literal while the database runs the DROP.
78
+ *
79
+ * The scan stops and reports an error, instead of guessing, when:
80
+ * - a string, quoted identifier, dollar-quoted string or block comment is not closed;
81
+ * - the text contains a NUL character;
82
+ * - a `--` comment contains a line break other than `\n` or `\r\n`;
83
+ * - a PostgreSQL `E'…'` string is followed by another quoted segment, which PostgreSQL can join to
84
+ * it and read with backslash escapes;
85
+ * - on SQL Server, a number is followed by `e` and a word character (`1EXEC` splits two ways).
86
+ *
87
+ * @param sql The clause, expression or query to read
88
+ * @param dialect The dialect whose lexical rules apply
89
+ */
90
+ export declare function ScanSQLForScreening(sql: string, dialect: SQLScreeningDialect): SQLScreeningScan;
91
+ //# sourceMappingURL=SQLScreeningScanner.d.ts.map