Skip to content

Commit 327ee96

Browse files
committed
fix(clickhouse): allow BETWEEN bounds in WHERE validation (OR-only literal rule) and dedupe JSDoc
1 parent 5ba735c commit 327ee96

1 file changed

Lines changed: 7 additions & 16 deletions

File tree

apps/sim/lib/core/security/input-validation.server.ts

Lines changed: 7 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -206,23 +206,14 @@ export async function validateDatabaseHost(
206206
}
207207
}
208208

209-
/**
210-
* Patterns that indicate SQL injection or an always-true ("tautology") condition
211-
* in a free-form WHERE clause supplied to a database mutation (UPDATE/DELETE) or
212-
* a filtered COUNT, where the value may originate from an LLM or untrusted
213-
* upstream workflow data.
214-
*
215-
* IMPORTANT: this is **defense-in-depth, not a security boundary**. A free-form
216-
* SQL condition cannot be exhaustively validated against every always-true
217-
* expression (e.g. `OR 2 > 1`, `OR (1)`, `OR NOT 0`, `OR length(x) >= 0`). The
218-
* real boundary is that the caller supplies their own database credentials and
219-
* could run equivalent SQL directly (e.g. via a raw-SQL/execute operation). This
220-
* guard exists to stop the easy, obvious ways an injected condition broadens a
221-
* mutation to every row.
222-
*/
223209
/**
224210
* Patterns run against the WHERE clause with string/identifier literals masked
225211
* out (so an attacker cannot smuggle `OR 1` or `; DROP` inside a quoted value).
212+
*
213+
* The connector-literal rules below are intentionally `OR`-only: only an
214+
* `OR <truthy>` term broadens a mutation to every row. `AND <number>` is a no-op
215+
* for broadening and is also exactly what `BETWEEN low AND high` produces, so
216+
* matching it would reject legitimate range filters (e.g. `id BETWEEN 1 AND 10`).
226217
*/
227218
const SQL_WHERE_MASKED_PATTERNS: readonly RegExp[] = [
228219
/;\s*\w/, // stacked statement
@@ -234,8 +225,8 @@ const SQL_WHERE_MASKED_PATTERNS: readonly RegExp[] = [
234225
/\b(?:sleep|pg_sleep|benchmark)\s*\(/i,
235226
/\b(\w+)\s*=\s*\1\b/i, // same (unquoted) operand both sides: x=x, 1=1
236227
/\b\d+(?:\.\d+)?\s*(?:=|==|<>|!=|<=|>=|<|>)\s*\d+(?:\.\d+)?\b/, // constant vs constant: 1=1, 1<2, 2>1
237-
/\b(?:or|and)\s+(?:true|false)\b/i, // OR TRUE / AND FALSE
238-
/\b(?:or|and)\s+\d+(?:\.\d+)?\b(?!\s*[=<>!+\-*/%])/i, // standalone truthy literal: OR 1, AND 42
228+
/\bor\s+(?:true|false)\b/i, // OR TRUE / OR FALSE
229+
/\bor\s+\d+(?:\.\d+)?\b(?!\s*[=<>!+\-*/%])/i, // standalone truthy literal after OR: OR 1, OR 42
239230
/^\s*(?:\d+(?:\.\d+)?|true|false)\s*$/i, // bare constant: "1" / "true" / "false"
240231
]
241232

0 commit comments

Comments
 (0)