DEV Community

SiteSecurityScore
SiteSecurityScore

Posted on • Originally published at sitesecurityscore.com

CSP for Third Party Scripts: The Practical Cheat Sheet for GA, Stripe, Intercom, and More

You ship a Content Security Policy. It works locally. Then marketing adds Google Tag Manager, payments goes live with Stripe, support turns on Intercom, and suddenly the browser console is screaming about violations and half your integrations are dead.

This is the number one reason CSP deployments fail in production. Not because the concept is hard, but because every third party service loads scripts from a different set of domains, and none of them make it easy to find.

This post is a working cheat sheet for the most common services. The full version with every table, nonce setup, and a strict-dynamic deep dive lives on the main guide: CSP for Third Party Scripts on SiteSecurityScore.

Why third party scripts break CSP

Every script, image, iframe, font, or XHR call your page makes has to match one of your CSP directives. Third party services typically trigger violations in four ways.

  1. They load a script from their CDN, which needs to be in script-src.
  2. That script fetches data from an API, which needs connect-src.
  3. It loads an iframe for a widget or checkout, which needs frame-src.
  4. It pulls images, fonts, or styles from their domain, which need img-src, font-src, and style-src.

Most services hit three of these four. That is why a CSP that looked clean on day one falls apart the moment someone wires up a tag manager.

Google Analytics 4 with GTM

script-src   www.googletagmanager.com www.google-analytics.com
connect-src  www.google-analytics.com analytics.google.com
             *.google-analytics.com *.analytics.google.com
img-src      www.google-analytics.com www.googletagmanager.com
Enter fullscreen mode Exit fullscreen mode

GTM injects inline scripts for every tag it fires. Do not reach for 'unsafe-inline'. Use a nonce on the initial GTM script and add 'strict-dynamic' to script-src, and GTM can load its tags without you allowlisting every third party it chains to.

Facebook Pixel

script-src   connect.facebook.net
connect-src  www.facebook.com
img-src      www.facebook.com
Enter fullscreen mode Exit fullscreen mode

Hotjar

script-src   static.hotjar.com script.hotjar.com
connect-src  *.hotjar.com *.hotjar.io wss://*.hotjar.com
img-src      *.hotjar.com
font-src     *.hotjar.com
frame-src    vars.hotjar.com
Enter fullscreen mode Exit fullscreen mode

Stripe

script-src   js.stripe.com
frame-src    js.stripe.com hooks.stripe.com
connect-src  api.stripe.com
img-src      *.stripe.com
Enter fullscreen mode Exit fullscreen mode

Stripe is strict. If you miss hooks.stripe.com in frame-src, 3D Secure challenges will silently fail and users will see a blank modal.

PayPal

script-src   www.paypal.com www.paypalobjects.com
frame-src    www.paypal.com www.sandbox.paypal.com
img-src      www.paypalobjects.com
connect-src  www.paypal.com
Enter fullscreen mode Exit fullscreen mode

Intercom

script-src   widget.intercom.io js.intercomcdn.com
connect-src  *.intercom.io wss://*.intercom.io api-iam.intercom.io
img-src      static.intercomassets.com *.intercomcdn.com
frame-src    intercom-sheets.com
font-src     js.intercomcdn.com
media-src    js.intercomcdn.com
Enter fullscreen mode Exit fullscreen mode

Watch the WebSocket entry on connect-src. If you forget wss://*.intercom.io, the widget loads but never connects, and support thinks the chat is broken.

HubSpot

script-src   js.hs-scripts.com js.hs-analytics.net js.hsadspixel.net
             js.hsforms.net js.hs-banner.com
connect-src  api.hubspot.com forms.hubspot.com
img-src      track.hubspot.com forms.hubspot.com
frame-src    app.hubspot.com
Enter fullscreen mode Exit fullscreen mode

Crisp Chat

script-src   client.crisp.chat
connect-src  client.crisp.chat wss://client.relay.crisp.chat
img-src      client.crisp.chat image.crisp.chat
style-src    client.crisp.chat
font-src     client.crisp.chat
Enter fullscreen mode Exit fullscreen mode

Google Fonts

style-src    fonts.googleapis.com
font-src     fonts.gstatic.com
Enter fullscreen mode Exit fullscreen mode

reCAPTCHA v3

script-src   www.google.com www.gstatic.com
frame-src    www.google.com
Enter fullscreen mode Exit fullscreen mode

YouTube embeds

frame-src    www.youtube.com www.youtube-nocookie.com
img-src      i.ytimg.com img.youtube.com
Enter fullscreen mode Exit fullscreen mode

Google Maps

script-src   maps.googleapis.com
frame-src    www.google.com maps.google.com
img-src      maps.googleapis.com maps.gstatic.com *.ggpht.com
connect-src  maps.googleapis.com
Enter fullscreen mode Exit fullscreen mode

A realistic SaaS CSP

Here is what a production CSP looks like when you stitch GTM, Stripe, Intercom, Google Fonts, and reCAPTCHA together.

Content-Security-Policy:
  default-src 'self';
  script-src 'self' 'nonce-{value}' 'strict-dynamic'
    www.googletagmanager.com
    www.google.com www.gstatic.com
    js.stripe.com
    widget.intercom.io js.intercomcdn.com;
  style-src 'self' 'nonce-{value}'
    fonts.googleapis.com;
  font-src 'self'
    fonts.gstatic.com
    js.intercomcdn.com;
  img-src 'self' data: https:
    www.googletagmanager.com
    www.google-analytics.com
    static.intercomassets.com *.intercomcdn.com
    *.stripe.com;
  connect-src 'self'
    www.google-analytics.com analytics.google.com
    *.google-analytics.com *.analytics.google.com
    api.stripe.com
    *.intercom.io wss://*.intercom.io;
  frame-src 'self'
    www.google.com
    js.stripe.com hooks.stripe.com
    intercom-sheets.com;
  media-src 'self'
    js.intercomcdn.com;
  report-uri /api/csp-report
Enter fullscreen mode Exit fullscreen mode

Long, but every line has a reason. No wildcards on broad domains, no 'unsafe-inline' in script-src, and strict-dynamic handles anything GTM or Intercom chain-loads at runtime.

A few rules that keep this sane

Prefer the most specific domain. js.stripe.com beats *.stripe.com, which beats https:. Every level of specificity is one less place an attacker can hide.

Do not dump everything into default-src. If Stripe only needs script-src and frame-src, leaving it in default-src silently allows it for images and fonts too.

Audit on a schedule. Google has migrated analytics endpoints multiple times. Stripe has added domains for new checkout flows. Your CSP from last year is probably already wrong.

Delete services you no longer use. Every allowlisted domain you forgot about is a domain an attacker can abuse if that vendor ever gets compromised.

How to find the domains you missed

Even with a cheat sheet, your site uses something this post does not list. Three ways to find out what.

Ship in report-only mode first. Set Content-Security-Policy-Report-Only with a report-uri or report-to endpoint. The browser sends you a structured violation for every blocked request without breaking production. Walk through the funnel, collect the reports, then tighten the policy. The full walkthrough is in How CSP Reporting Works.

Use DevTools Network tab. Open the site, reload with the Network tab open, sort by domain. Every external host your page touches is a candidate for your CSP.

Scan the site. SiteSecurityScore parses your live CSP, shows which directives are set, and flags gaps for the services it detects on your page.

Free tools that helped me write this

These are all on the main site and free to use, no account needed.

  • CSP Generator builds a policy from a checklist of services and gives you a working Content-Security-Policy header.
  • CSP Reporting Guide shows how to stand up a report-uri endpoint and interpret the violation payloads.
  • HSTS Generator for the other header everyone gets wrong.
  • Permissions Policy Generator for locking down camera, mic, geolocation, and payment APIs.
  • CORS Generator for the adjacent problem of cross origin requests.
  • The main security scanner grades headers, TLS, cookies, CSP coverage, and third party script exposure in one pass.

TL;DR

Third party scripts break CSP because nobody documents the exact domains their service needs across every directive. Steal the tables above, start in report-only mode, watch your violation reports, and iterate until production is quiet.

Full version with nonce setup, strict-dynamic explanation, and a complete FAQ is on the main guide: CSP for Third Party Scripts on SiteSecurityScore.

If your site is already in production and you want a quick read on whether your CSP actually covers the scripts you are loading, run it through the scanner. Takes about 10 seconds.

Top comments (0)