Skip to content

Commit d5bea5f

Browse files
fix(table): escape LIKE wildcards in $contains filter values (#3949)
The $contains filter operator builds an ILIKE pattern but does not escape LIKE wildcard characters (%, _) in user-provided values. This causes incorrect, over-broad query results when the search value contains these characters. For example, filtering with { name: { $contains: "100%" } } matches any row where name contains "100" followed by anything, not just the literal "100%". Escape %, _, and \ in the value before interpolating into the ILIKE pattern so that they match literally. Co-authored-by: Waleed <walif6@gmail.com> Co-authored-by: lawrence3699 <lawrence3699@users.noreply.github.com>
1 parent f46886e commit d5bea5f

File tree

1 file changed

+6
-1
lines changed

1 file changed

+6
-1
lines changed

apps/sim/lib/table/sql.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -322,10 +322,15 @@ function buildComparisonClause(
322322
return sql`(${sql.raw(`${tableName}.data->>'${escapedField}'`)})::numeric ${sql.raw(operator)} ${value}`
323323
}
324324

325+
/** Escapes LIKE/ILIKE wildcard characters so they match literally */
326+
function escapeLikePattern(value: string): string {
327+
return value.replace(/[\\%_]/g, '\\$&')
328+
}
329+
325330
/** Builds case-insensitive pattern match: `data->>'field' ILIKE '%value%'` */
326331
function buildContainsClause(tableName: string, field: string, value: string): SQL {
327332
const escapedField = field.replace(/'/g, "''")
328-
return sql`${sql.raw(`${tableName}.data->>'${escapedField}'`)} ILIKE ${`%${value}%`}`
333+
return sql`${sql.raw(`${tableName}.data->>'${escapedField}'`)} ILIKE ${`%${escapeLikePattern(value)}%`}`
329334
}
330335

331336
/**

0 commit comments

Comments
 (0)