All files / src/lib csp-allowlist.ts

100% Statements 1/1
100% Branches 0/0
100% Functions 0/0
100% Lines 1/1

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98                    2x                                                                                                                                                                              
// Third-party origins permitted by the marketplace Content Security Policy.
//
// One entry per directive. To enable a new marketing/analytics vendor, append
// its origins to the relevant arrays here — no middleware logic changes
// required. Keep entries grouped by vendor (with a comment) so a future reader
// can see who needs what and remove a vendor cleanly when retiring a tag.
//
// Wildcards (`https://*.example.com`) are honoured by CSP — use them sparingly
// and only when the vendor genuinely uses dynamic subdomains.
 
export const CSP_ALLOWLIST = {
	scriptSrc: [
		// Google Tag Manager — bootstrap script (gtm.js)
		"https://www.googletagmanager.com",
		// Contentsquare — tag script injected by the GTM Contentsquare template
		// (t.contentsquare.net/uxa/<tagId>.js) + in-app features
		"https://*.contentsquare.net",
		"https://app.contentsquare.com",
		// Meta (Facebook/Instagram) Pixel — bootstrap script (fbevents.js)
		"https://connect.facebook.net",
		// Google Ads — the remarketing/conversion script gtag injects as a
		// <script> (`viewthroughconversion/...&fmt=4`). Ads was "pre-allowed"
		// below for images and connections only, so this one was blocked on
		// every page load with a console error and no remarketing signal.
		"https://googleads.g.doubleclick.net",
	],
	imgSrc: [
		// Google Tag Manager (no-script fallback iframe pings, debug pixels)
		"https://www.googletagmanager.com",
		// Google Analytics 4 — collect endpoint pixel beacons
		"https://www.google-analytics.com",
		"https://*.analytics.google.com",
		// Google Ads / Doubleclick — remarketing + conversion pixels (pre-allowed
		// so Ads ships later via GTM admin without another CSP PR)
		"https://*.g.doubleclick.net",
		"https://www.google.com",
		"https://www.google.co.in",
		// Contentsquare — replay asset pixels
		"https://*.contentsquare.net",
		// Meta Pixel — <noscript> fallback tracking pixel (facebook.com/tr)
		"https://www.facebook.com",
	],
	connectSrc: [
		// Google Analytics 4 — measurement protocol XHR/beacon
		"https://www.google-analytics.com",
		"https://*.analytics.google.com",
		"https://*.google-analytics.com",
		// The APEX host, which the wildcard above does NOT cover: CSP's
		// `*.analytics.google.com` matches a subdomain and never the bare name.
		// GA4 posts its page_view to `analytics.google.com/g/collect`, so this
		// one line is the difference between that beacon landing and being
		// refused with nothing but a console error.
		"https://analytics.google.com",
		// GA4 cross-domain / engagement-ping endpoint (gtm.js routes some
		// `g/collect` beacons here for ads attribution). Without this CSP
		// blocks every page load with a `Refused to connect to
		// 'https://www.google.com/g/collect'` console error.
		"https://www.google.com",
		"https://www.google.co.in",
		// Google Ads / Doubleclick — conversion linker XHR
		"https://stats.g.doubleclick.net",
		// Google Ads — the conversion beacon the remarketing script posts once
		// it is allowed to run at all (`ad.doubleclick.net/ccm/s/collect`).
		// Invisible until the script was unblocked, because a script that never
		// executes never reveals what it would have called.
		"https://ad.doubleclick.net",
		// Contentsquare — session-replay/analytics beacons
		"https://*.contentsquare.net",
		"https://*.contentsquare.com",
		// Meta Pixel — fetch/sendBeacon event calls (facebook.com/tr) +
		// fbevents.js plugin/extension fetches
		"https://www.facebook.com",
		"https://connect.facebook.net",
	],
	frameSrc: [
		// Google Tag Manager — <noscript> iframe fallback
		"https://www.googletagmanager.com",
		// Google Ads — conversion iframe
		"https://td.doubleclick.net",
		// Meta Pixel — the hidden iframe it posts events into. See formAction.
		"https://www.facebook.com",
	],
	/**
	 * `form-action`, which is NOT covered by `connect-src`.
	 *
	 * The Meta Pixel does not send its events with fetch. When it cannot use a
	 * beacon it builds a hidden <form>, points it at `facebook.com/tr/` and
	 * submits it into an iframe. `form-action 'self'` blocks the submit and
	 * `frame-src` blocks the iframe, which is two directives to satisfy for one
	 * request — miss either and the pixel goes quiet with only a console error
	 * to show for it.
	 */
	formAction: [
		// Meta Pixel — event transport (facebook.com/tr/)
		"https://www.facebook.com",
	],
} as const;