From 2815483324915946aec8d2cd7a71199c7d9c2d73 Mon Sep 17 00:00:00 2001 From: waleedlatif1 Date: Mon, 22 Sep 2025 11:58:36 -0700 Subject: [PATCH] fix(csp): added terms, privacy, & logo URLs to CSP --- apps/sim/lib/security/csp.ts | 36 +++++++++++++++++++++++++----------- 1 file changed, 25 insertions(+), 11 deletions(-) diff --git a/apps/sim/lib/security/csp.ts b/apps/sim/lib/security/csp.ts index 0d43859291..be5002cf73 100644 --- a/apps/sim/lib/security/csp.ts +++ b/apps/sim/lib/security/csp.ts @@ -2,9 +2,17 @@ import { env, getEnv } from '../env' /** * Content Security Policy (CSP) configuration builder - * This creates a more maintainable and readable CSP configuration */ +function getHostnameFromUrl(url: string | undefined): string[] { + if (!url) return [] + try { + return [`https://${new URL(url).hostname}`] + } catch { + return [] + } +} + export interface CSPDirectives { 'default-src'?: string[] 'script-src'?: string[] @@ -43,7 +51,6 @@ export const buildTimeCSPDirectives: CSPDirectives = { 'style-src': ["'self'", "'unsafe-inline'", 'https://fonts.googleapis.com'], 'img-src': [ - 'https://agentics.epiqglobal.com', "'self'", 'data:', 'blob:', @@ -66,6 +73,7 @@ export const buildTimeCSPDirectives: CSPDirectives = { : []), 'https://*.amazonaws.com', 'https://*.blob.core.windows.net', + ...getHostnameFromUrl(env.NEXT_PUBLIC_BRAND_LOGO_URL), ], 'media-src': ["'self'", 'blob:'], @@ -98,14 +106,12 @@ export const buildTimeCSPDirectives: CSPDirectives = { 'https://*.vercel.app', 'wss://*.vercel.app', 'https://pro.ip-api.com', + ...getHostnameFromUrl(env.NEXT_PUBLIC_BRAND_LOGO_URL), + ...getHostnameFromUrl(env.NEXT_PUBLIC_PRIVACY_URL), + ...getHostnameFromUrl(env.NEXT_PUBLIC_TERMS_URL), ], - // Google Picker and Drive integration - 'frame-src': [ - 'https://drive.google.com', - 'https://docs.google.com', // Required for Google Picker - 'https://*.google.com', - ], + 'frame-src': ['https://drive.google.com', 'https://docs.google.com', 'https://*.google.com'], 'frame-ancestors': ["'self'"], 'form-action': ["'self'"], @@ -120,7 +126,6 @@ export function buildCSPString(directives: CSPDirectives): string { return Object.entries(directives) .map(([directive, sources]) => { if (!sources || sources.length === 0) return '' - // Filter out empty strings const validSources = sources.filter((source: string) => source && source.trim() !== '') if (validSources.length === 0) return '' return `${directive} ${validSources.join(' ')}` @@ -140,14 +145,23 @@ export function generateRuntimeCSP(): string { const appUrl = getEnv('NEXT_PUBLIC_APP_URL') || '' const ollamaUrl = getEnv('OLLAMA_URL') || 'http://localhost:11434' + const brandLogoDomains = getHostnameFromUrl(getEnv('NEXT_PUBLIC_BRAND_LOGO_URL')) + const privacyDomains = getHostnameFromUrl(getEnv('NEXT_PUBLIC_PRIVACY_URL')) + const termsDomains = getHostnameFromUrl(getEnv('NEXT_PUBLIC_TERMS_URL')) + + const allDynamicDomains = [...brandLogoDomains, ...privacyDomains, ...termsDomains] + const uniqueDynamicDomains = Array.from(new Set(allDynamicDomains)) + const dynamicDomainsStr = uniqueDynamicDomains.join(' ') + const brandLogoDomain = brandLogoDomains[0] || '' + return ` default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' https://*.google.com https://apis.google.com https://*.vercel-scripts.com https://*.vercel-insights.com https://vercel.live https://*.vercel.live https://vercel.com https://*.vercel.app https://vitals.vercel-insights.com https://b2bjsstore.s3.us-west-2.amazonaws.com; 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://*.public.blob.vercel-storage.com; + img-src 'self' data: blob: https://*.googleusercontent.com https://*.google.com https://*.atlassian.com https://cdn.discordapp.com https://*.githubusercontent.com https://*.public.blob.vercel-storage.com ${brandLogoDomain}; media-src 'self' blob:; font-src 'self' https://fonts.gstatic.com; - connect-src 'self' ${appUrl} ${ollamaUrl} ${socketUrl} ${socketWsUrl} https://*.up.railway.app wss://*.up.railway.app 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://*.vercel-insights.com https://vitals.vercel-insights.com https://*.atlassian.com https://*.supabase.co https://vercel.live https://*.vercel.live https://vercel.com https://*.vercel.app wss://*.vercel.app https://pro.ip-api.com; + connect-src 'self' ${appUrl} ${ollamaUrl} ${socketUrl} ${socketWsUrl} https://*.up.railway.app wss://*.up.railway.app 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://*.vercel-insights.com https://vitals.vercel-insights.com https://*.atlassian.com https://*.supabase.co https://vercel.live https://*.vercel.live https://vercel.com https://*.vercel.app wss://*.vercel.app https://pro.ip-api.com ${dynamicDomainsStr}; frame-src https://drive.google.com https://docs.google.com https://*.google.com; frame-ancestors 'self'; form-action 'self';