feat(security): add GTM and GA domains to CSP for hosted environments (#4024)

* feat(security): add GTM and GA domains to CSP for hosted environments

* lint
This commit is contained in:
Waleed
2026-04-07 13:49:35 -07:00
committed by GitHub
parent cd3cb871be
commit e2d4d0edfe
2 changed files with 24 additions and 5 deletions

View File

@@ -19,6 +19,7 @@ vi.mock('@/lib/core/config/env', () =>
vi.mock('@/lib/core/config/feature-flags', () => ({
isDev: false,
isHosted: false,
isReactGrabEnabled: false,
}))

View File

@@ -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,24 @@ 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';