Managing Third-Party Resources with CSP
Most websites depend on third-party resources: analytics, advertising, social widgets, payment processors, and more. However, these third-party resources can be security vulnerabilities and conflict with Content Security Policy restrictions.
Balancing functionality with security requires careful planning and configuration of CSP rules for third-party resources.
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 unique nonce for each request -->
<script nonce="abc123def456">
// Third-party injected code
</script>
CSP:
script-src 'self' 'nonce-abc123def456'
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>
CSP with SRI:
script-src 'self' https://code.jquery.com 'require-sri-for'
The browser verifies the hash before executing. If content doesn't match, it's blocked.
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
Content-Security-Policy-Report-Only:
default-src 'self';
script-src 'self' [third-party domains];
report-uri /csp-report
Monitor violations to ensure all third-party resources are whitelisted.
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.

