From 1ce2a2f1e7e75877ea1d705be52617ddb1e04c43 Mon Sep 17 00:00:00 2001 From: Waleed Latif Date: Tue, 7 Apr 2026 13:24:33 -0700 Subject: [PATCH 1/2] feat(security): add GTM and GA domains to CSP for hosted environments --- apps/sim/lib/core/security/csp.test.ts | 1 + apps/sim/lib/core/security/csp.ts | 30 +++++++++++++++++++++----- 2 files changed, 26 insertions(+), 5 deletions(-) diff --git a/apps/sim/lib/core/security/csp.test.ts b/apps/sim/lib/core/security/csp.test.ts index b8661ea5e53..2a6fb3da95d 100644 --- a/apps/sim/lib/core/security/csp.test.ts +++ b/apps/sim/lib/core/security/csp.test.ts @@ -19,6 +19,7 @@ vi.mock('@/lib/core/config/env', () => vi.mock('@/lib/core/config/feature-flags', () => ({ isDev: false, + isHosted: false, isReactGrabEnabled: false, })) diff --git a/apps/sim/lib/core/security/csp.ts b/apps/sim/lib/core/security/csp.ts index 3eafb959499..5c65fc877d9 100644 --- a/apps/sim/lib/core/security/csp.ts +++ b/apps/sim/lib/core/security/csp.ts @@ -1,5 +1,5 @@ import { env, getEnv } from '../config/env' -import { isDev, isReactGrabEnabled } from '../config/feature-flags' +import { isDev, isHosted, isReactGrabEnabled } from '../config/feature-flags' /** * Content Security Policy (CSP) configuration builder @@ -42,6 +42,7 @@ export const buildTimeCSPDirectives: CSPDirectives = { 'https://assets.onedollarstats.com', 'https://challenges.cloudflare.com', ...(isReactGrabEnabled ? ['https://unpkg.com'] : []), + ...(isHosted ? ['https://www.googletagmanager.com', 'https://www.google-analytics.com'] : []), ], 'style-src': ["'self'", "'unsafe-inline'", 'https://fonts.googleapis.com'], @@ -59,6 +60,7 @@ export const buildTimeCSPDirectives: CSPDirectives = { 'https://s3.amazonaws.com', 'https://github.com/*', 'https://collector.onedollarstats.com', + ...(isHosted ? ['https://www.googletagmanager.com', 'https://www.google-analytics.com'] : []), ...(env.S3_BUCKET_NAME && env.AWS_REGION ? [`https://${env.S3_BUCKET_NAME}.s3.${env.AWS_REGION}.amazonaws.com`] : []), @@ -105,6 +107,13 @@ export const buildTimeCSPDirectives: CSPDirectives = { 'https://github.com/*', 'https://challenges.cloudflare.com', 'https://collector.onedollarstats.com', + ...(isHosted + ? [ + 'https://www.googletagmanager.com', + 'https://*.google-analytics.com', + 'https://*.analytics.google.com', + ] + : []), ...getHostnameFromUrl(env.NEXT_PUBLIC_BRAND_LOGO_URL), ...getHostnameFromUrl(env.NEXT_PUBLIC_PRIVACY_URL), ...getHostnameFromUrl(env.NEXT_PUBLIC_TERMS_URL), @@ -116,6 +125,7 @@ export const buildTimeCSPDirectives: CSPDirectives = { 'https://drive.google.com', 'https://docs.google.com', 'https://*.google.com', + ...(isHosted ? ['https://www.googletagmanager.com'] : []), ], 'frame-ancestors': ["'self'"], @@ -171,16 +181,26 @@ export function generateRuntimeCSP(): string { const brandLogoDomain = brandLogoDomains[0] || '' const brandFaviconDomain = brandFaviconDomains[0] || '' const reactGrabScript = isReactGrabEnabled ? 'https://unpkg.com' : '' + const gtmScript = isHosted + ? 'https://www.googletagmanager.com https://www.google-analytics.com' + : '' + const gtmConnect = isHosted + ? 'https://www.googletagmanager.com https://*.google-analytics.com https://*.analytics.google.com' + : '' + const gtmImg = isHosted + ? 'https://www.googletagmanager.com https://www.google-analytics.com' + : '' + const gtmFrame = isHosted ? 'https://www.googletagmanager.com' : '' return ` default-src 'self'; - script-src 'self' 'unsafe-inline' 'unsafe-eval' https://*.google.com https://apis.google.com https://assets.onedollarstats.com https://challenges.cloudflare.com ${reactGrabScript}; + script-src 'self' 'unsafe-inline' 'unsafe-eval' https://*.google.com https://apis.google.com https://assets.onedollarstats.com https://challenges.cloudflare.com ${reactGrabScript} ${gtmScript}; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; - img-src 'self' data: blob: https://*.googleusercontent.com https://*.google.com https://*.atlassian.com https://cdn.discordapp.com https://*.githubusercontent.com https://*.s3.amazonaws.com https://s3.amazonaws.com https://*.amazonaws.com https://*.blob.core.windows.net https://github.com/* https://collector.onedollarstats.com ${brandLogoDomain} ${brandFaviconDomain}; + img-src 'self' data: blob: https://*.googleusercontent.com https://*.google.com https://*.atlassian.com https://cdn.discordapp.com https://*.githubusercontent.com https://*.s3.amazonaws.com https://s3.amazonaws.com https://*.amazonaws.com https://*.blob.core.windows.net https://github.com/* https://collector.onedollarstats.com ${gtmImg} ${brandLogoDomain} ${brandFaviconDomain}; media-src 'self' blob:; font-src 'self' https://fonts.gstatic.com; - connect-src 'self' ${appUrl} ${ollamaUrl} ${socketUrl} ${socketWsUrl} https://api.browser-use.com https://api.exa.ai https://api.firecrawl.dev https://*.googleapis.com https://*.amazonaws.com https://*.s3.amazonaws.com https://*.blob.core.windows.net https://api.github.com https://github.com/* https://*.atlassian.com https://*.supabase.co https://challenges.cloudflare.com https://collector.onedollarstats.com ${dynamicDomainsStr}; - frame-src 'self' https://challenges.cloudflare.com https://drive.google.com https://docs.google.com https://*.google.com; + connect-src 'self' ${appUrl} ${ollamaUrl} ${socketUrl} ${socketWsUrl} https://api.browser-use.com https://api.exa.ai https://api.firecrawl.dev https://*.googleapis.com https://*.amazonaws.com https://*.s3.amazonaws.com https://*.blob.core.windows.net https://api.github.com https://github.com/* https://*.atlassian.com https://*.supabase.co https://challenges.cloudflare.com https://collector.onedollarstats.com ${gtmConnect} ${dynamicDomainsStr}; + frame-src 'self' https://challenges.cloudflare.com https://drive.google.com https://docs.google.com https://*.google.com ${gtmFrame}; frame-ancestors 'self'; form-action 'self'; base-uri 'self'; From f5d919d9f68b331f2f555185429afbaee824f9c0 Mon Sep 17 00:00:00 2001 From: Waleed Latif Date: Tue, 7 Apr 2026 13:39:46 -0700 Subject: [PATCH 2/2] lint --- apps/sim/lib/core/security/csp.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/apps/sim/lib/core/security/csp.ts b/apps/sim/lib/core/security/csp.ts index 5c65fc877d9..b92d6a3a09a 100644 --- a/apps/sim/lib/core/security/csp.ts +++ b/apps/sim/lib/core/security/csp.ts @@ -187,9 +187,7 @@ export function generateRuntimeCSP(): string { const gtmConnect = isHosted ? 'https://www.googletagmanager.com https://*.google-analytics.com https://*.analytics.google.com' : '' - const gtmImg = isHosted - ? 'https://www.googletagmanager.com https://www.google-analytics.com' - : '' + const gtmImg = isHosted ? 'https://www.googletagmanager.com https://www.google-analytics.com' : '' const gtmFrame = isHosted ? 'https://www.googletagmanager.com' : '' return `