From 17ff6ccf7d88948cd22f81fa0492396fff6eb7a1 Mon Sep 17 00:00:00 2001 From: Richie McIlroy <33632126+richiemcilroy@users.noreply.github.com> Date: Fri, 19 Jun 2026 09:46:52 +0100 Subject: [PATCH] fix(web): escape backslashes in analytics ClickHouse literals --- apps/web/actions/videos/get-analytics.ts | 6 +++++- apps/web/app/(org)/dashboard/analytics/data.ts | 6 +++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/apps/web/actions/videos/get-analytics.ts b/apps/web/actions/videos/get-analytics.ts index 35e1ca743aa..83726d52eb2 100644 --- a/apps/web/actions/videos/get-analytics.ts +++ b/apps/web/actions/videos/get-analytics.ts @@ -13,7 +13,11 @@ const MIN_RANGE_DAYS = 1; const MAX_RANGE_DAYS = 90; const DEFAULT_RANGE_DAYS = MAX_RANGE_DAYS; -const escapeLiteral = (value: string) => value.replace(/'/g, "''"); +// Escape backslashes BEFORE quotes: ClickHouse honors C-style `\'` inside +// single-quoted literals, so doubling quotes alone lets a trailing backslash +// neutralise the doubled quote and break out of the string (SQL injection). +const escapeLiteral = (value: string) => + value.replace(/\\/g, "\\\\").replace(/'/g, "''"); const formatDate = (date: Date) => date.toISOString().slice(0, 10); const formatDateTime = (date: Date) => date.toISOString().slice(0, 19).replace("T", " "); diff --git a/apps/web/app/(org)/dashboard/analytics/data.ts b/apps/web/app/(org)/dashboard/analytics/data.ts index a4aca4b2aaa..a2d487544f4 100644 --- a/apps/web/app/(org)/dashboard/analytics/data.ts +++ b/apps/web/app/(org)/dashboard/analytics/data.ts @@ -47,7 +47,11 @@ const ROLLING_RANGE_CONFIG: Record< const LIFETIME_FALLBACK_DAYS = 30; -const escapeLiteral = (value: string) => value.replace(/'/g, "''"); +// Escape backslashes BEFORE quotes: ClickHouse honors C-style `\'` inside +// single-quoted literals, so doubling quotes alone lets a trailing backslash +// neutralise the doubled quote and break out of the string (SQL injection). +const escapeLiteral = (value: string) => + value.replace(/\\/g, "\\\\").replace(/'/g, "''"); const toDateString = (date: Date) => date.toISOString().slice(0, 10); const toDateTimeString = (date: Date) => date.toISOString().slice(0, 19).replace("T", " ");