<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: SiteSecurityScore</title>
    <description>The latest articles on DEV Community by SiteSecurityScore (@sitesecurityscore).</description>
    <link>https://dev.to/sitesecurityscore</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3888925%2F53ab2cd1-d467-44d5-a60c-fdc9920c3e55.png</url>
      <title>DEV Community: SiteSecurityScore</title>
      <link>https://dev.to/sitesecurityscore</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/sitesecurityscore"/>
    <language>en</language>
    <item>
      <title>CSP for Third Party Scripts: The Practical Cheat Sheet for GA, Stripe, Intercom, and More</title>
      <dc:creator>SiteSecurityScore</dc:creator>
      <pubDate>Mon, 20 Apr 2026 13:16:42 +0000</pubDate>
      <link>https://dev.to/sitesecurityscore/csp-for-third-party-scripts-the-practical-cheat-sheet-for-ga-stripe-intercom-and-more-1gh8</link>
      <guid>https://dev.to/sitesecurityscore/csp-for-third-party-scripts-the-practical-cheat-sheet-for-ga-stripe-intercom-and-more-1gh8</guid>
      <description>&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;This post is a working cheat sheet for the most common services. The full version with every table, nonce setup, and a &lt;code&gt;strict-dynamic&lt;/code&gt; deep dive lives on the main guide: &lt;a href="https://www.sitesecurityscore.com/learning-center/how-to-add-csp-for-third-party-scripts" rel="noopener noreferrer"&gt;CSP for Third Party Scripts on SiteSecurityScore&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why third party scripts break CSP
&lt;/h2&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;They load a script from their CDN, which needs to be in &lt;code&gt;script-src&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;That script fetches data from an API, which needs &lt;code&gt;connect-src&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;It loads an iframe for a widget or checkout, which needs &lt;code&gt;frame-src&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;It pulls images, fonts, or styles from their domain, which need &lt;code&gt;img-src&lt;/code&gt;, &lt;code&gt;font-src&lt;/code&gt;, and &lt;code&gt;style-src&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;h2&gt;
  
  
  Google Analytics 4 with GTM
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight conf"&gt;&lt;code&gt;&lt;span class="n"&gt;script&lt;/span&gt;-&lt;span class="n"&gt;src&lt;/span&gt;   &lt;span class="n"&gt;www&lt;/span&gt;.&lt;span class="n"&gt;googletagmanager&lt;/span&gt;.&lt;span class="n"&gt;com&lt;/span&gt; &lt;span class="n"&gt;www&lt;/span&gt;.&lt;span class="n"&gt;google&lt;/span&gt;-&lt;span class="n"&gt;analytics&lt;/span&gt;.&lt;span class="n"&gt;com&lt;/span&gt;
&lt;span class="n"&gt;connect&lt;/span&gt;-&lt;span class="n"&gt;src&lt;/span&gt;  &lt;span class="n"&gt;www&lt;/span&gt;.&lt;span class="n"&gt;google&lt;/span&gt;-&lt;span class="n"&gt;analytics&lt;/span&gt;.&lt;span class="n"&gt;com&lt;/span&gt; &lt;span class="n"&gt;analytics&lt;/span&gt;.&lt;span class="n"&gt;google&lt;/span&gt;.&lt;span class="n"&gt;com&lt;/span&gt;
             *.&lt;span class="n"&gt;google&lt;/span&gt;-&lt;span class="n"&gt;analytics&lt;/span&gt;.&lt;span class="n"&gt;com&lt;/span&gt; *.&lt;span class="n"&gt;analytics&lt;/span&gt;.&lt;span class="n"&gt;google&lt;/span&gt;.&lt;span class="n"&gt;com&lt;/span&gt;
&lt;span class="n"&gt;img&lt;/span&gt;-&lt;span class="n"&gt;src&lt;/span&gt;      &lt;span class="n"&gt;www&lt;/span&gt;.&lt;span class="n"&gt;google&lt;/span&gt;-&lt;span class="n"&gt;analytics&lt;/span&gt;.&lt;span class="n"&gt;com&lt;/span&gt; &lt;span class="n"&gt;www&lt;/span&gt;.&lt;span class="n"&gt;googletagmanager&lt;/span&gt;.&lt;span class="n"&gt;com&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;h2&gt;
  
  
  Facebook Pixel
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight conf"&gt;&lt;code&gt;&lt;span class="n"&gt;script&lt;/span&gt;-&lt;span class="n"&gt;src&lt;/span&gt;   &lt;span class="n"&gt;connect&lt;/span&gt;.&lt;span class="n"&gt;facebook&lt;/span&gt;.&lt;span class="n"&gt;net&lt;/span&gt;
&lt;span class="n"&gt;connect&lt;/span&gt;-&lt;span class="n"&gt;src&lt;/span&gt;  &lt;span class="n"&gt;www&lt;/span&gt;.&lt;span class="n"&gt;facebook&lt;/span&gt;.&lt;span class="n"&gt;com&lt;/span&gt;
&lt;span class="n"&gt;img&lt;/span&gt;-&lt;span class="n"&gt;src&lt;/span&gt;      &lt;span class="n"&gt;www&lt;/span&gt;.&lt;span class="n"&gt;facebook&lt;/span&gt;.&lt;span class="n"&gt;com&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Hotjar
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight conf"&gt;&lt;code&gt;&lt;span class="n"&gt;script&lt;/span&gt;-&lt;span class="n"&gt;src&lt;/span&gt;   &lt;span class="n"&gt;static&lt;/span&gt;.&lt;span class="n"&gt;hotjar&lt;/span&gt;.&lt;span class="n"&gt;com&lt;/span&gt; &lt;span class="n"&gt;script&lt;/span&gt;.&lt;span class="n"&gt;hotjar&lt;/span&gt;.&lt;span class="n"&gt;com&lt;/span&gt;
&lt;span class="n"&gt;connect&lt;/span&gt;-&lt;span class="n"&gt;src&lt;/span&gt;  *.&lt;span class="n"&gt;hotjar&lt;/span&gt;.&lt;span class="n"&gt;com&lt;/span&gt; *.&lt;span class="n"&gt;hotjar&lt;/span&gt;.&lt;span class="n"&gt;io&lt;/span&gt; &lt;span class="n"&gt;wss&lt;/span&gt;://*.&lt;span class="n"&gt;hotjar&lt;/span&gt;.&lt;span class="n"&gt;com&lt;/span&gt;
&lt;span class="n"&gt;img&lt;/span&gt;-&lt;span class="n"&gt;src&lt;/span&gt;      *.&lt;span class="n"&gt;hotjar&lt;/span&gt;.&lt;span class="n"&gt;com&lt;/span&gt;
&lt;span class="n"&gt;font&lt;/span&gt;-&lt;span class="n"&gt;src&lt;/span&gt;     *.&lt;span class="n"&gt;hotjar&lt;/span&gt;.&lt;span class="n"&gt;com&lt;/span&gt;
&lt;span class="n"&gt;frame&lt;/span&gt;-&lt;span class="n"&gt;src&lt;/span&gt;    &lt;span class="n"&gt;vars&lt;/span&gt;.&lt;span class="n"&gt;hotjar&lt;/span&gt;.&lt;span class="n"&gt;com&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Stripe
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight conf"&gt;&lt;code&gt;&lt;span class="n"&gt;script&lt;/span&gt;-&lt;span class="n"&gt;src&lt;/span&gt;   &lt;span class="n"&gt;js&lt;/span&gt;.&lt;span class="n"&gt;stripe&lt;/span&gt;.&lt;span class="n"&gt;com&lt;/span&gt;
&lt;span class="n"&gt;frame&lt;/span&gt;-&lt;span class="n"&gt;src&lt;/span&gt;    &lt;span class="n"&gt;js&lt;/span&gt;.&lt;span class="n"&gt;stripe&lt;/span&gt;.&lt;span class="n"&gt;com&lt;/span&gt; &lt;span class="n"&gt;hooks&lt;/span&gt;.&lt;span class="n"&gt;stripe&lt;/span&gt;.&lt;span class="n"&gt;com&lt;/span&gt;
&lt;span class="n"&gt;connect&lt;/span&gt;-&lt;span class="n"&gt;src&lt;/span&gt;  &lt;span class="n"&gt;api&lt;/span&gt;.&lt;span class="n"&gt;stripe&lt;/span&gt;.&lt;span class="n"&gt;com&lt;/span&gt;
&lt;span class="n"&gt;img&lt;/span&gt;-&lt;span class="n"&gt;src&lt;/span&gt;      *.&lt;span class="n"&gt;stripe&lt;/span&gt;.&lt;span class="n"&gt;com&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;h2&gt;
  
  
  PayPal
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight conf"&gt;&lt;code&gt;&lt;span class="n"&gt;script&lt;/span&gt;-&lt;span class="n"&gt;src&lt;/span&gt;   &lt;span class="n"&gt;www&lt;/span&gt;.&lt;span class="n"&gt;paypal&lt;/span&gt;.&lt;span class="n"&gt;com&lt;/span&gt; &lt;span class="n"&gt;www&lt;/span&gt;.&lt;span class="n"&gt;paypalobjects&lt;/span&gt;.&lt;span class="n"&gt;com&lt;/span&gt;
&lt;span class="n"&gt;frame&lt;/span&gt;-&lt;span class="n"&gt;src&lt;/span&gt;    &lt;span class="n"&gt;www&lt;/span&gt;.&lt;span class="n"&gt;paypal&lt;/span&gt;.&lt;span class="n"&gt;com&lt;/span&gt; &lt;span class="n"&gt;www&lt;/span&gt;.&lt;span class="n"&gt;sandbox&lt;/span&gt;.&lt;span class="n"&gt;paypal&lt;/span&gt;.&lt;span class="n"&gt;com&lt;/span&gt;
&lt;span class="n"&gt;img&lt;/span&gt;-&lt;span class="n"&gt;src&lt;/span&gt;      &lt;span class="n"&gt;www&lt;/span&gt;.&lt;span class="n"&gt;paypalobjects&lt;/span&gt;.&lt;span class="n"&gt;com&lt;/span&gt;
&lt;span class="n"&gt;connect&lt;/span&gt;-&lt;span class="n"&gt;src&lt;/span&gt;  &lt;span class="n"&gt;www&lt;/span&gt;.&lt;span class="n"&gt;paypal&lt;/span&gt;.&lt;span class="n"&gt;com&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Intercom
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight conf"&gt;&lt;code&gt;&lt;span class="n"&gt;script&lt;/span&gt;-&lt;span class="n"&gt;src&lt;/span&gt;   &lt;span class="n"&gt;widget&lt;/span&gt;.&lt;span class="n"&gt;intercom&lt;/span&gt;.&lt;span class="n"&gt;io&lt;/span&gt; &lt;span class="n"&gt;js&lt;/span&gt;.&lt;span class="n"&gt;intercomcdn&lt;/span&gt;.&lt;span class="n"&gt;com&lt;/span&gt;
&lt;span class="n"&gt;connect&lt;/span&gt;-&lt;span class="n"&gt;src&lt;/span&gt;  *.&lt;span class="n"&gt;intercom&lt;/span&gt;.&lt;span class="n"&gt;io&lt;/span&gt; &lt;span class="n"&gt;wss&lt;/span&gt;://*.&lt;span class="n"&gt;intercom&lt;/span&gt;.&lt;span class="n"&gt;io&lt;/span&gt; &lt;span class="n"&gt;api&lt;/span&gt;-&lt;span class="n"&gt;iam&lt;/span&gt;.&lt;span class="n"&gt;intercom&lt;/span&gt;.&lt;span class="n"&gt;io&lt;/span&gt;
&lt;span class="n"&gt;img&lt;/span&gt;-&lt;span class="n"&gt;src&lt;/span&gt;      &lt;span class="n"&gt;static&lt;/span&gt;.&lt;span class="n"&gt;intercomassets&lt;/span&gt;.&lt;span class="n"&gt;com&lt;/span&gt; *.&lt;span class="n"&gt;intercomcdn&lt;/span&gt;.&lt;span class="n"&gt;com&lt;/span&gt;
&lt;span class="n"&gt;frame&lt;/span&gt;-&lt;span class="n"&gt;src&lt;/span&gt;    &lt;span class="n"&gt;intercom&lt;/span&gt;-&lt;span class="n"&gt;sheets&lt;/span&gt;.&lt;span class="n"&gt;com&lt;/span&gt;
&lt;span class="n"&gt;font&lt;/span&gt;-&lt;span class="n"&gt;src&lt;/span&gt;     &lt;span class="n"&gt;js&lt;/span&gt;.&lt;span class="n"&gt;intercomcdn&lt;/span&gt;.&lt;span class="n"&gt;com&lt;/span&gt;
&lt;span class="n"&gt;media&lt;/span&gt;-&lt;span class="n"&gt;src&lt;/span&gt;    &lt;span class="n"&gt;js&lt;/span&gt;.&lt;span class="n"&gt;intercomcdn&lt;/span&gt;.&lt;span class="n"&gt;com&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;h2&gt;
  
  
  HubSpot
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight conf"&gt;&lt;code&gt;&lt;span class="n"&gt;script&lt;/span&gt;-&lt;span class="n"&gt;src&lt;/span&gt;   &lt;span class="n"&gt;js&lt;/span&gt;.&lt;span class="n"&gt;hs&lt;/span&gt;-&lt;span class="n"&gt;scripts&lt;/span&gt;.&lt;span class="n"&gt;com&lt;/span&gt; &lt;span class="n"&gt;js&lt;/span&gt;.&lt;span class="n"&gt;hs&lt;/span&gt;-&lt;span class="n"&gt;analytics&lt;/span&gt;.&lt;span class="n"&gt;net&lt;/span&gt; &lt;span class="n"&gt;js&lt;/span&gt;.&lt;span class="n"&gt;hsadspixel&lt;/span&gt;.&lt;span class="n"&gt;net&lt;/span&gt;
             &lt;span class="n"&gt;js&lt;/span&gt;.&lt;span class="n"&gt;hsforms&lt;/span&gt;.&lt;span class="n"&gt;net&lt;/span&gt; &lt;span class="n"&gt;js&lt;/span&gt;.&lt;span class="n"&gt;hs&lt;/span&gt;-&lt;span class="n"&gt;banner&lt;/span&gt;.&lt;span class="n"&gt;com&lt;/span&gt;
&lt;span class="n"&gt;connect&lt;/span&gt;-&lt;span class="n"&gt;src&lt;/span&gt;  &lt;span class="n"&gt;api&lt;/span&gt;.&lt;span class="n"&gt;hubspot&lt;/span&gt;.&lt;span class="n"&gt;com&lt;/span&gt; &lt;span class="n"&gt;forms&lt;/span&gt;.&lt;span class="n"&gt;hubspot&lt;/span&gt;.&lt;span class="n"&gt;com&lt;/span&gt;
&lt;span class="n"&gt;img&lt;/span&gt;-&lt;span class="n"&gt;src&lt;/span&gt;      &lt;span class="n"&gt;track&lt;/span&gt;.&lt;span class="n"&gt;hubspot&lt;/span&gt;.&lt;span class="n"&gt;com&lt;/span&gt; &lt;span class="n"&gt;forms&lt;/span&gt;.&lt;span class="n"&gt;hubspot&lt;/span&gt;.&lt;span class="n"&gt;com&lt;/span&gt;
&lt;span class="n"&gt;frame&lt;/span&gt;-&lt;span class="n"&gt;src&lt;/span&gt;    &lt;span class="n"&gt;app&lt;/span&gt;.&lt;span class="n"&gt;hubspot&lt;/span&gt;.&lt;span class="n"&gt;com&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Crisp Chat
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight conf"&gt;&lt;code&gt;&lt;span class="n"&gt;script&lt;/span&gt;-&lt;span class="n"&gt;src&lt;/span&gt;   &lt;span class="n"&gt;client&lt;/span&gt;.&lt;span class="n"&gt;crisp&lt;/span&gt;.&lt;span class="n"&gt;chat&lt;/span&gt;
&lt;span class="n"&gt;connect&lt;/span&gt;-&lt;span class="n"&gt;src&lt;/span&gt;  &lt;span class="n"&gt;client&lt;/span&gt;.&lt;span class="n"&gt;crisp&lt;/span&gt;.&lt;span class="n"&gt;chat&lt;/span&gt; &lt;span class="n"&gt;wss&lt;/span&gt;://&lt;span class="n"&gt;client&lt;/span&gt;.&lt;span class="n"&gt;relay&lt;/span&gt;.&lt;span class="n"&gt;crisp&lt;/span&gt;.&lt;span class="n"&gt;chat&lt;/span&gt;
&lt;span class="n"&gt;img&lt;/span&gt;-&lt;span class="n"&gt;src&lt;/span&gt;      &lt;span class="n"&gt;client&lt;/span&gt;.&lt;span class="n"&gt;crisp&lt;/span&gt;.&lt;span class="n"&gt;chat&lt;/span&gt; &lt;span class="n"&gt;image&lt;/span&gt;.&lt;span class="n"&gt;crisp&lt;/span&gt;.&lt;span class="n"&gt;chat&lt;/span&gt;
&lt;span class="n"&gt;style&lt;/span&gt;-&lt;span class="n"&gt;src&lt;/span&gt;    &lt;span class="n"&gt;client&lt;/span&gt;.&lt;span class="n"&gt;crisp&lt;/span&gt;.&lt;span class="n"&gt;chat&lt;/span&gt;
&lt;span class="n"&gt;font&lt;/span&gt;-&lt;span class="n"&gt;src&lt;/span&gt;     &lt;span class="n"&gt;client&lt;/span&gt;.&lt;span class="n"&gt;crisp&lt;/span&gt;.&lt;span class="n"&gt;chat&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Google Fonts
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight conf"&gt;&lt;code&gt;&lt;span class="n"&gt;style&lt;/span&gt;-&lt;span class="n"&gt;src&lt;/span&gt;    &lt;span class="n"&gt;fonts&lt;/span&gt;.&lt;span class="n"&gt;googleapis&lt;/span&gt;.&lt;span class="n"&gt;com&lt;/span&gt;
&lt;span class="n"&gt;font&lt;/span&gt;-&lt;span class="n"&gt;src&lt;/span&gt;     &lt;span class="n"&gt;fonts&lt;/span&gt;.&lt;span class="n"&gt;gstatic&lt;/span&gt;.&lt;span class="n"&gt;com&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  reCAPTCHA v3
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight conf"&gt;&lt;code&gt;&lt;span class="n"&gt;script&lt;/span&gt;-&lt;span class="n"&gt;src&lt;/span&gt;   &lt;span class="n"&gt;www&lt;/span&gt;.&lt;span class="n"&gt;google&lt;/span&gt;.&lt;span class="n"&gt;com&lt;/span&gt; &lt;span class="n"&gt;www&lt;/span&gt;.&lt;span class="n"&gt;gstatic&lt;/span&gt;.&lt;span class="n"&gt;com&lt;/span&gt;
&lt;span class="n"&gt;frame&lt;/span&gt;-&lt;span class="n"&gt;src&lt;/span&gt;    &lt;span class="n"&gt;www&lt;/span&gt;.&lt;span class="n"&gt;google&lt;/span&gt;.&lt;span class="n"&gt;com&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  YouTube embeds
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight conf"&gt;&lt;code&gt;&lt;span class="n"&gt;frame&lt;/span&gt;-&lt;span class="n"&gt;src&lt;/span&gt;    &lt;span class="n"&gt;www&lt;/span&gt;.&lt;span class="n"&gt;youtube&lt;/span&gt;.&lt;span class="n"&gt;com&lt;/span&gt; &lt;span class="n"&gt;www&lt;/span&gt;.&lt;span class="n"&gt;youtube&lt;/span&gt;-&lt;span class="n"&gt;nocookie&lt;/span&gt;.&lt;span class="n"&gt;com&lt;/span&gt;
&lt;span class="n"&gt;img&lt;/span&gt;-&lt;span class="n"&gt;src&lt;/span&gt;      &lt;span class="n"&gt;i&lt;/span&gt;.&lt;span class="n"&gt;ytimg&lt;/span&gt;.&lt;span class="n"&gt;com&lt;/span&gt; &lt;span class="n"&gt;img&lt;/span&gt;.&lt;span class="n"&gt;youtube&lt;/span&gt;.&lt;span class="n"&gt;com&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Google Maps
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight conf"&gt;&lt;code&gt;&lt;span class="n"&gt;script&lt;/span&gt;-&lt;span class="n"&gt;src&lt;/span&gt;   &lt;span class="n"&gt;maps&lt;/span&gt;.&lt;span class="n"&gt;googleapis&lt;/span&gt;.&lt;span class="n"&gt;com&lt;/span&gt;
&lt;span class="n"&gt;frame&lt;/span&gt;-&lt;span class="n"&gt;src&lt;/span&gt;    &lt;span class="n"&gt;www&lt;/span&gt;.&lt;span class="n"&gt;google&lt;/span&gt;.&lt;span class="n"&gt;com&lt;/span&gt; &lt;span class="n"&gt;maps&lt;/span&gt;.&lt;span class="n"&gt;google&lt;/span&gt;.&lt;span class="n"&gt;com&lt;/span&gt;
&lt;span class="n"&gt;img&lt;/span&gt;-&lt;span class="n"&gt;src&lt;/span&gt;      &lt;span class="n"&gt;maps&lt;/span&gt;.&lt;span class="n"&gt;googleapis&lt;/span&gt;.&lt;span class="n"&gt;com&lt;/span&gt; &lt;span class="n"&gt;maps&lt;/span&gt;.&lt;span class="n"&gt;gstatic&lt;/span&gt;.&lt;span class="n"&gt;com&lt;/span&gt; *.&lt;span class="n"&gt;ggpht&lt;/span&gt;.&lt;span class="n"&gt;com&lt;/span&gt;
&lt;span class="n"&gt;connect&lt;/span&gt;-&lt;span class="n"&gt;src&lt;/span&gt;  &lt;span class="n"&gt;maps&lt;/span&gt;.&lt;span class="n"&gt;googleapis&lt;/span&gt;.&lt;span class="n"&gt;com&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  A realistic SaaS CSP
&lt;/h2&gt;

&lt;p&gt;Here is what a production CSP looks like when you stitch GTM, Stripe, Intercom, Google Fonts, and reCAPTCHA together.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight conf"&gt;&lt;code&gt;&lt;span class="n"&gt;Content&lt;/span&gt;-&lt;span class="n"&gt;Security&lt;/span&gt;-&lt;span class="n"&gt;Policy&lt;/span&gt;:
  &lt;span class="n"&gt;default&lt;/span&gt;-&lt;span class="n"&gt;src&lt;/span&gt; &lt;span class="s1"&gt;'self'&lt;/span&gt;;
  &lt;span class="n"&gt;script&lt;/span&gt;-&lt;span class="n"&gt;src&lt;/span&gt; &lt;span class="s1"&gt;'self'&lt;/span&gt; &lt;span class="s1"&gt;'nonce-{value}'&lt;/span&gt; &lt;span class="s1"&gt;'strict-dynamic'&lt;/span&gt;
    &lt;span class="n"&gt;www&lt;/span&gt;.&lt;span class="n"&gt;googletagmanager&lt;/span&gt;.&lt;span class="n"&gt;com&lt;/span&gt;
    &lt;span class="n"&gt;www&lt;/span&gt;.&lt;span class="n"&gt;google&lt;/span&gt;.&lt;span class="n"&gt;com&lt;/span&gt; &lt;span class="n"&gt;www&lt;/span&gt;.&lt;span class="n"&gt;gstatic&lt;/span&gt;.&lt;span class="n"&gt;com&lt;/span&gt;
    &lt;span class="n"&gt;js&lt;/span&gt;.&lt;span class="n"&gt;stripe&lt;/span&gt;.&lt;span class="n"&gt;com&lt;/span&gt;
    &lt;span class="n"&gt;widget&lt;/span&gt;.&lt;span class="n"&gt;intercom&lt;/span&gt;.&lt;span class="n"&gt;io&lt;/span&gt; &lt;span class="n"&gt;js&lt;/span&gt;.&lt;span class="n"&gt;intercomcdn&lt;/span&gt;.&lt;span class="n"&gt;com&lt;/span&gt;;
  &lt;span class="n"&gt;style&lt;/span&gt;-&lt;span class="n"&gt;src&lt;/span&gt; &lt;span class="s1"&gt;'self'&lt;/span&gt; &lt;span class="s1"&gt;'nonce-{value}'&lt;/span&gt;
    &lt;span class="n"&gt;fonts&lt;/span&gt;.&lt;span class="n"&gt;googleapis&lt;/span&gt;.&lt;span class="n"&gt;com&lt;/span&gt;;
  &lt;span class="n"&gt;font&lt;/span&gt;-&lt;span class="n"&gt;src&lt;/span&gt; &lt;span class="s1"&gt;'self'&lt;/span&gt;
    &lt;span class="n"&gt;fonts&lt;/span&gt;.&lt;span class="n"&gt;gstatic&lt;/span&gt;.&lt;span class="n"&gt;com&lt;/span&gt;
    &lt;span class="n"&gt;js&lt;/span&gt;.&lt;span class="n"&gt;intercomcdn&lt;/span&gt;.&lt;span class="n"&gt;com&lt;/span&gt;;
  &lt;span class="n"&gt;img&lt;/span&gt;-&lt;span class="n"&gt;src&lt;/span&gt; &lt;span class="s1"&gt;'self'&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;: &lt;span class="n"&gt;https&lt;/span&gt;:
    &lt;span class="n"&gt;www&lt;/span&gt;.&lt;span class="n"&gt;googletagmanager&lt;/span&gt;.&lt;span class="n"&gt;com&lt;/span&gt;
    &lt;span class="n"&gt;www&lt;/span&gt;.&lt;span class="n"&gt;google&lt;/span&gt;-&lt;span class="n"&gt;analytics&lt;/span&gt;.&lt;span class="n"&gt;com&lt;/span&gt;
    &lt;span class="n"&gt;static&lt;/span&gt;.&lt;span class="n"&gt;intercomassets&lt;/span&gt;.&lt;span class="n"&gt;com&lt;/span&gt; *.&lt;span class="n"&gt;intercomcdn&lt;/span&gt;.&lt;span class="n"&gt;com&lt;/span&gt;
    *.&lt;span class="n"&gt;stripe&lt;/span&gt;.&lt;span class="n"&gt;com&lt;/span&gt;;
  &lt;span class="n"&gt;connect&lt;/span&gt;-&lt;span class="n"&gt;src&lt;/span&gt; &lt;span class="s1"&gt;'self'&lt;/span&gt;
    &lt;span class="n"&gt;www&lt;/span&gt;.&lt;span class="n"&gt;google&lt;/span&gt;-&lt;span class="n"&gt;analytics&lt;/span&gt;.&lt;span class="n"&gt;com&lt;/span&gt; &lt;span class="n"&gt;analytics&lt;/span&gt;.&lt;span class="n"&gt;google&lt;/span&gt;.&lt;span class="n"&gt;com&lt;/span&gt;
    *.&lt;span class="n"&gt;google&lt;/span&gt;-&lt;span class="n"&gt;analytics&lt;/span&gt;.&lt;span class="n"&gt;com&lt;/span&gt; *.&lt;span class="n"&gt;analytics&lt;/span&gt;.&lt;span class="n"&gt;google&lt;/span&gt;.&lt;span class="n"&gt;com&lt;/span&gt;
    &lt;span class="n"&gt;api&lt;/span&gt;.&lt;span class="n"&gt;stripe&lt;/span&gt;.&lt;span class="n"&gt;com&lt;/span&gt;
    *.&lt;span class="n"&gt;intercom&lt;/span&gt;.&lt;span class="n"&gt;io&lt;/span&gt; &lt;span class="n"&gt;wss&lt;/span&gt;://*.&lt;span class="n"&gt;intercom&lt;/span&gt;.&lt;span class="n"&gt;io&lt;/span&gt;;
  &lt;span class="n"&gt;frame&lt;/span&gt;-&lt;span class="n"&gt;src&lt;/span&gt; &lt;span class="s1"&gt;'self'&lt;/span&gt;
    &lt;span class="n"&gt;www&lt;/span&gt;.&lt;span class="n"&gt;google&lt;/span&gt;.&lt;span class="n"&gt;com&lt;/span&gt;
    &lt;span class="n"&gt;js&lt;/span&gt;.&lt;span class="n"&gt;stripe&lt;/span&gt;.&lt;span class="n"&gt;com&lt;/span&gt; &lt;span class="n"&gt;hooks&lt;/span&gt;.&lt;span class="n"&gt;stripe&lt;/span&gt;.&lt;span class="n"&gt;com&lt;/span&gt;
    &lt;span class="n"&gt;intercom&lt;/span&gt;-&lt;span class="n"&gt;sheets&lt;/span&gt;.&lt;span class="n"&gt;com&lt;/span&gt;;
  &lt;span class="n"&gt;media&lt;/span&gt;-&lt;span class="n"&gt;src&lt;/span&gt; &lt;span class="s1"&gt;'self'&lt;/span&gt;
    &lt;span class="n"&gt;js&lt;/span&gt;.&lt;span class="n"&gt;intercomcdn&lt;/span&gt;.&lt;span class="n"&gt;com&lt;/span&gt;;
  &lt;span class="n"&gt;report&lt;/span&gt;-&lt;span class="n"&gt;uri&lt;/span&gt; /&lt;span class="n"&gt;api&lt;/span&gt;/&lt;span class="n"&gt;csp&lt;/span&gt;-&lt;span class="n"&gt;report&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;h2&gt;
  
  
  A few rules that keep this sane
&lt;/h2&gt;

&lt;p&gt;Prefer the most specific domain. &lt;code&gt;js.stripe.com&lt;/code&gt; beats &lt;code&gt;*.stripe.com&lt;/code&gt;, which beats &lt;code&gt;https:&lt;/code&gt;. Every level of specificity is one less place an attacker can hide.&lt;/p&gt;

&lt;p&gt;Do not dump everything into &lt;code&gt;default-src&lt;/code&gt;. If Stripe only needs &lt;code&gt;script-src&lt;/code&gt; and &lt;code&gt;frame-src&lt;/code&gt;, leaving it in &lt;code&gt;default-src&lt;/code&gt; silently allows it for images and fonts too.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to find the domains you missed
&lt;/h2&gt;

&lt;p&gt;Even with a cheat sheet, your site uses something this post does not list. Three ways to find out what.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Ship in report-only mode first.&lt;/strong&gt; Set &lt;code&gt;Content-Security-Policy-Report-Only&lt;/code&gt; with a &lt;code&gt;report-uri&lt;/code&gt; or &lt;code&gt;report-to&lt;/code&gt; 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 &lt;a href="https://www.sitesecurityscore.com/learning-center/csp-reporting-guide" rel="noopener noreferrer"&gt;How CSP Reporting Works&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Use DevTools Network tab.&lt;/strong&gt; Open the site, reload with the Network tab open, sort by domain. Every external host your page touches is a candidate for your CSP.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Scan the site.&lt;/strong&gt; &lt;a href="https://www.sitesecurityscore.com/" rel="noopener noreferrer"&gt;SiteSecurityScore&lt;/a&gt; parses your live CSP, shows which directives are set, and flags gaps for the services it detects on your page.&lt;/p&gt;

&lt;h2&gt;
  
  
  Free tools that helped me write this
&lt;/h2&gt;

&lt;p&gt;These are all on the main site and free to use, no account needed.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://www.sitesecurityscore.com/learning-center/csp-generator-guide" rel="noopener noreferrer"&gt;CSP Generator&lt;/a&gt; builds a policy from a checklist of services and gives you a working &lt;code&gt;Content-Security-Policy&lt;/code&gt; header.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.sitesecurityscore.com/learning-center/csp-reporting-guide" rel="noopener noreferrer"&gt;CSP Reporting Guide&lt;/a&gt; shows how to stand up a &lt;code&gt;report-uri&lt;/code&gt; endpoint and interpret the violation payloads.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.sitesecurityscore.com/learning-center/hsts-generator-guide" rel="noopener noreferrer"&gt;HSTS Generator&lt;/a&gt; for the other header everyone gets wrong.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.sitesecurityscore.com/learning-center/permissions-policy-generator-guide" rel="noopener noreferrer"&gt;Permissions Policy Generator&lt;/a&gt; for locking down camera, mic, geolocation, and payment APIs.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.sitesecurityscore.com/learning-center/cors-generator-guide" rel="noopener noreferrer"&gt;CORS Generator&lt;/a&gt; for the adjacent problem of cross origin requests.&lt;/li&gt;
&lt;li&gt;The main &lt;a href="https://www.sitesecurityscore.com/" rel="noopener noreferrer"&gt;security scanner&lt;/a&gt; grades headers, TLS, cookies, CSP coverage, and third party script exposure in one pass.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;Full version with nonce setup, &lt;code&gt;strict-dynamic&lt;/code&gt; explanation, and a complete FAQ is on the main guide: &lt;a href="https://www.sitesecurityscore.com/learning-center/how-to-add-csp-for-third-party-scripts" rel="noopener noreferrer"&gt;CSP for Third Party Scripts on SiteSecurityScore&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If your site is already in production and you want a quick read on whether your CSP actually covers the scripts you are loading, &lt;a href="https://www.sitesecurityscore.com/" rel="noopener noreferrer"&gt;run it through the scanner&lt;/a&gt;. Takes about 10 seconds.&lt;/p&gt;

</description>
      <category>security</category>
      <category>webdev</category>
      <category>javascript</category>
      <category>devops</category>
    </item>
  </channel>
</rss>
