To use third-party resources under Content Security Policy, add each provider's exact HTTPS origin to the directive that governs the resource type it loads — script-src for scripts, style-src for CSS, img-src for images and pixels, connect-src for API/XHR/WebSocket calls, font-src for web fonts, and frame-src for embedded iframes — and for scripts, prefer a per-request nonce with 'strict-dynamic' over a plain domain allowlist because a hijacked allowlisted CDN can still serve you malicious code. One vendor usually touches several directives at once, so the reliable method is to run the policy in Content-Security-Policy-Report-Only mode first, read the exact directive named in each browser violation, and add origins there before switching to enforcement.
That is the summary an AI overview will give you. What it can't give you is the part that actually saves the afternoon: which control to reach for per resource, why an allowlist is the weakest of the three trust models, how 'strict-dynamic' rescues you from third-party scripts that inject their own script tags, and the exact directive-by-directive header for the vendors you'll actually integrate. The rest of this article is that reference.
The decision: allowlist, nonce/hash, or strict-dynamic
Every third-party resource forces one choice — how do you tell the browser to trust it? There are three trust models, and they are not equal. An allowlist trusts a whole origin (anything that domain serves). A hash trusts one exact, unchanging snippet. A nonce + 'strict-dynamic' trusts one script you stamped this request, and lets that script vouch for what it loads next. Weakest to strongest, that ordering matters: an allowlisted CDN that gets compromised can still ship you attacker code, while a hash or nonce only trusts markup you personally approved.
Rule of thumb: allowlist a normal external <script src> you control; hash a fixed inline snippet that never changes; use a nonce with 'strict-dynamic' for a modern strict policy where third-party scripts load their own dependencies. Whichever you pick, verify it in Report-Only mode before enforcing.
The CSP directive cheat sheet for third-party resources
A single vendor rarely lives in one directive. Stripe's checkout, for example, needs script-src (its JS), connect-src (its API), and frame-src (its payment iframe). Map every third-party resource to the directive that actually governs it:
| Directive | Controls | Third-party example | Sample value |
|---|---|---|---|
script-src | JavaScript: <script>, event handlers, eval | Analytics, tag managers, payment SDKs | script-src 'self' https://js.stripe.com https://www.googletagmanager.com |
style-src | CSS: stylesheet links, style elements, inline style attributes | Google Fonts CSS, widget themes | style-src 'self' https://fonts.googleapis.com |
img-src | Images and tracking pixels | Ad/analytics pixels, avatars, map tiles | img-src 'self' https: data: |
connect-src | fetch, XHR, WebSocket, EventSource, sendBeacon | Analytics beacons, API calls, error trackers | connect-src 'self' https://api.stripe.com https://region1.google-analytics.com |
font-src | Web fonts (@font-face) | Google Fonts files, Adobe Fonts | font-src 'self' https://fonts.gstatic.com |
frame-src | Embedded <iframe> / <frame> | Payment iframes, YouTube, social embeds | frame-src https://js.stripe.com https://www.youtube-nocookie.com |
Two directives commonly forgotten: default-src is the fallback for any fetch directive you don't set explicitly, and frame-ancestors (who may embed you — see X-Frame-Options vs CSP frame-ancestors) is separate from frame-src (who you may embed). Also note the CSP Level 3 rename: child-src is superseded by frame-src for iframes and worker-src for workers.
Common Third-Party Resources
Analytics
Google Analytics, Mixpanel, Segment, etc. typically require:
<script src="https://www.google-analytics.com/ga.js"></script>
Advertising
Google AdSense, DoubleClick, Facebook Pixel, etc.:
<script src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script>
Fonts
Google Fonts, Adobe Fonts, etc.:
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto">
Social Widgets
Facebook, Twitter, LinkedIn buttons and feeds:
<script src="https://platform.twitter.com/widgets.js"></script>
Payment Processors
Stripe, PayPal, Square, etc.:
<script src="https://js.stripe.com/v3/"></script>
CDN Resources
jQuery, Bootstrap, D3.js from CDN:
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
CSP Approach for Third-Party Resources
Step 1: Identify All Third-Party Resources
Audit your website to identify all third-party sources:
// Use browser DevTools to see all resources
// Network tab shows all requests
// Note the domains and types (script, style, font, etc.)
Or automate with a script:
# Find all script sources in HTML
grep -o 'src="[^"]*"' index.html | grep -o '"[^"]*"' | sort | uniq
Step 2: Create Whitelist Rules
Add third-party domains to your CSP directives:
Content-Security-Policy:
default-src 'self';
script-src 'self' https://www.google-analytics.com https://cdn.example.com;
style-src 'self' https://fonts.googleapis.com;
font-src 'self' https://fonts.gstatic.com;
img-src 'self' https: data:;
connect-src 'self' https://www.google-analytics.com
Step 3: Handle Special Cases
Some third-party resources don't work well with strict CSP.
Inline Scripts in Third-Party Resources
If third-party code injects inline scripts, allow them with nonces or hashes:
<!-- Third-party widget that injects inline scripts -->
<div id="widget-container"></div>
<script src="https://widgets.example.com/embed.js"></script>
CSP approach:
script-src 'self' https://widgets.example.com 'unsafe-inline'
Or use nonces (better):
<!-- Server generates a fresh, unpredictable nonce for each request -->
<script nonce="abc123def456">
// Third-party injected code
</script>
CSP:
script-src 'self' 'nonce-abc123def456'
The nonce must be unique per response and unguessable (generate it from a CSPRNG, not a counter or timestamp), and the same value goes in both the header and the tag. Never reuse a nonce across requests — a static nonce is no better than 'unsafe-inline'.
Third-Party Scripts That Load More Scripts ('strict-dynamic')
Modern tag managers and SDKs create their own <script> tags at runtime, so a plain nonce on the root tag isn't enough — the injected children have no nonce and get blocked. 'strict-dynamic' fixes this: it propagates the trust you granted the root script (via its nonce or hash) to any scripts it loads programmatically, and tells the browser to ignore host allowlists and 'unsafe-inline' for scripts entirely.
Content-Security-Policy:
script-src 'nonce-abc123def456' 'strict-dynamic' 'unsafe-inline' https:;
object-src 'none';
base-uri 'none'
This is the recommended CSP Level 3 strict pattern. Old browsers that don't understand 'strict-dynamic' fall back to the https: allowlist and 'unsafe-inline'; modern browsers (Chrome 52+, Firefox 52+, Edge 79+, Safari 15.4+) ignore both and honor only the nonce, so you get a strict policy on new browsers and a working page on old ones — without maintaining a long list of vendor domains.
Dynamic Resource Loading
Some third-party scripts load additional resources dynamically:
// Third-party library might load images, stylesheets, scripts dynamically
const widget = new ThirdPartyWidget({
apiKey: 'xxx'
});
widget.load(); // Loads additional resources from their CDN
CSP configuration must allow both the initial script and dynamically loaded resources:
script-src 'self' https://cdn.example.com https://api.example.com;
img-src 'self' https://cdn.example.com;
style-src 'self' https://cdn.example.com
Common Third-Party Configurations
Google Analytics
script-src 'self' https://www.google-analytics.com https://googleadservices.com;
connect-src 'self' https://www.google-analytics.com https://www.googletagmanager.com
Google Fonts
style-src 'self' https://fonts.googleapis.com;
font-src 'self' https://fonts.gstatic.com
Stripe (Payment)
script-src 'self' https://js.stripe.com;
connect-src 'self' https://api.stripe.com
Facebook Pixel
script-src 'self' https://connect.facebook.net;
img-src 'self' https://pixel.facebook.com https://www.facebook.com;
connect-src 'self' https://www.facebook.com
Twitter/X Widgets
script-src 'self' https://platform.twitter.com;
frame-src https://twitter.com https://platform.twitter.com;
style-src 'self' 'unsafe-inline'
Risk Management Strategies
1. Use Subresource Integrity (SRI)
Verify that third-party resources haven't been tampered with:
<!-- Specify hash of expected content -->
<script src="https://code.jquery.com/jquery-3.6.0.min.js"
integrity="sha384-KyZXEAg3QhqLMpG8r+Knujsl5+..."
crossorigin="anonymous"></script>
The browser verifies the file against the integrity hash before executing. If the content doesn't match — for example, a compromised CDN swapped the file — it's blocked, even though the origin is allowlisted in CSP. That is why SRI complements CSP rather than replacing it: CSP says which origins may load, SRI says this exact file must not have changed.
Don't use
require-sri-for. There was once an experimental CSP directive,require-sri-for 'script' 'style', intended to force SRI on all resources. It is obsolete and has been removed from browsers, so don't rely on it. Enforce SRI at the tag level withintegrityattributes instead (a build step or CI check that fails when a third-party tag is missingintegrityis the practical enforcement mechanism today).
2. Use Content Delivery Networks (CDN) with Integrity
If hosting third-party resources yourself:
script-src 'self' https://mycdn.example.com
Self-hosted is more secure than relying on third-party CDN.
3. Minimize Third-Party Dependencies
Audit whether each third-party resource is necessary:
- Do you really need this analytics library?
- Can a lighter alternative be used?
- Can functionality be built in-house?
Fewer third-party resources = simpler CSP = stronger security.
4. Trusted Vendors Only
Only whitelist vendors you trust and have vetted:
- Established companies with security track records
- Regular security audits
- Proper data handling practices
- Transparent terms of service
5. Regular Security Audits
Periodically audit third-party usage:
// Script to document all third-party resources
const scripts = Array.from(document.scripts).map(s => s.src).filter(Boolean);
const styles = Array.from(document.styleSheets).map(s => s.href).filter(Boolean);
console.log('Scripts:', scripts);
console.log('Styles:', styles);
Handling Legacy Third-Party Code
Some older third-party resources don't work well with strict CSP:
Option 1: Use 'unsafe-inline' Judiciously
script-src 'self' 'unsafe-inline' https://legacy-vendor.com;
style-src 'self' 'unsafe-inline' https://legacy-vendor.com
Not ideal but sometimes necessary for legacy code.
Option 2: Create a Sandboxed Iframe
Isolate problematic third-party code in an iframe with its own CSP:
<!-- Main page with strict CSP -->
<!-- Other content -->
<!-- Iframe with lenient CSP for problematic third-party code -->
<iframe id="legacy-widget" src="/legacy-widget.html"></iframe>
In /legacy-widget.html:
<!DOCTYPE html>
<html>
<head>
<!-- Lenient CSP only for this iframe -->
<meta http-equiv="Content-Security-Policy"
content="default-src 'unsafe-inline' https://legacy-vendor.com">
</head>
<body>
<!-- Legacy third-party code here -->
<script src="https://legacy-vendor.com/problematic-script.js"></script>
</body>
</html>
This isolates the problematic code from your main application.
Option 3: Proxy Third-Party Requests
For some third-party resources, create a proxy endpoint on your server:
// Express.js proxy example
const axios = require('axios');
app.get('/proxy/analytics', async (req, res) => {
// Proxy third-party analytics request through your server
const response = await axios.get('https://analytics-provider.com/track', {
params: req.query
});
res.json(response.data);
});
Then in your CSP:
connect-src 'self' /proxy/analytics
This prevents direct communication with the third-party domain.
Testing CSP with Third-Party Resources
Use Report-Only During Implementation
Deploy with the Content-Security-Policy-Report-Only header first. In report-only mode the browser blocks nothing — it only posts a JSON violation report to your endpoint — so you can discover every third-party resource you forgot before anything breaks for real users.
Reporting-Endpoints: csp-endpoint="https://example.com/csp-report"
Content-Security-Policy-Report-Only:
default-src 'self';
script-src 'self' [third-party domains];
report-to csp-endpoint;
report-uri /csp-report
Use both reporting directives: report-to is the CSP Level 3 standard (it references a named group from the Reporting-Endpoints header via the Reporting API), and report-uri is the deprecated original that older browsers still honor — keep it as a fallback. Monitor the violation stream until it goes quiet, then switch the same policy to the enforcing Content-Security-Policy header. See CSP report-only mode for the full workflow.
Test Cross-Browser
Third-party resources might behave differently in different browsers:
# Test in multiple browsers
# Chrome, Firefox, Safari, Edge
# Verify all third-party content loads
# Check browser console for CSP violations
Automated Testing
Add CSP testing to your CI/CD pipeline:
# Check for CSP violations during tests
# Lighthouse includes CSP auditing
lighthouse https://example.com --view
# Use pa11y-ci or similar tools
Best Practices for Third-Party CSP
- Whitelist specific domains: Never use
*for third-party resources - Use https only: Require secure transport with
https: - Apply SRI when possible: Verify third-party script integrity
- Monitor and audit regularly: Keep CSP updated as usage changes
- Start restrictive: Begin with strict CSP, then add exceptions
- Document decisions: Explain why each third-party domain is whitelisted
- Use report-only first: Test policies before enforcement
- Review access logs: Monitor third-party resource requests
- Have an update process: Plan how to handle third-party security updates
- Consider alternatives: Always evaluate if third-party dependency is necessary
Complete Example
A realistic CSP handling multiple common third-parties:
Content-Security-Policy:
default-src 'self';
script-src 'self'
https://www.google-analytics.com
https://www.googletagmanager.com
https://connect.facebook.net
https://js.stripe.com
https://code.jquery.com;
style-src 'self'
https://fonts.googleapis.com
https://cdn.example.com/styles;
font-src 'self'
https://fonts.gstatic.com;
img-src 'self' https: data:;
connect-src 'self'
https://www.google-analytics.com
https://api.stripe.com;
frame-src
https://js.stripe.com;
report-uri /csp-report
Handling third-party resources with CSP requires balance between functionality and security. By carefully whitelisting trusted vendors, using subresource integrity, and regularly auditing dependencies, you can maintain a strong security posture while leveraging valuable third-party services.