TL;DR
CSP tells browsers which resources are allowed to load. It's defense in depth against XSS - even if injection exists, CSP can block the malicious script. Start with report-only mode, fix violations, then enforce. These prompts help you build a working CSP.
Basic CSP Setup
Set up Content Security Policy headers for my application.
Platform: Next.js/Vercel/Netlify/Express
Start with a restrictive policy:
- default-src 'self' (only same origin)
- script-src 'self' (no inline scripts)
- style-src 'self' 'unsafe-inline' (most CSS needs this)
- img-src 'self' data: https: (images from anywhere via HTTPS)
- font-src 'self' (fonts from same origin)
- connect-src 'self' (API calls to same origin)
- frame-ancestors 'none' (prevent clickjacking)
For Next.js, set in next.config.js headers. For Vercel, use vercel.json headers. For Express, use helmet middleware.
Start with Content-Security-Policy-Report-Only to test before switching to enforcing Content-Security-Policy.
Allow Third-Party Services
Update my CSP to allow these third-party services:
Services I use:
- Google Analytics
- Google Fonts
- Stripe
- Intercom/Crisp
- YouTube embeds
- CDN (cloudflare, jsdelivr)
For each service, add the minimum required origins:
Google Analytics: script-src: https://www.googletagmanager.com connect-src: https://www.google-analytics.com
Google Fonts: style-src: https://fonts.googleapis.com font-src: https://fonts.gstatic.com
Stripe: script-src: https://js.stripe.com frame-src: https://js.stripe.com https://hooks.stripe.com
Generate the complete CSP header combining all services I've checked above.
Avoid 'unsafe-inline' for scripts: It defeats much of CSP's protection. Use nonces or hashes instead. 'unsafe-inline' for styles is often necessary but less dangerous.
Use Nonces for Inline Scripts
Implement CSP nonces for inline scripts.
Framework: Next.js/Express
Nonces allow specific inline scripts while blocking injected ones.
Flow:
- Generate random nonce per request
- Add nonce to CSP header: script-src 'nonce-{random}'
- Add nonce attribute to allowed scripts
- Injected scripts without nonce are blocked
Implementation: // Generate nonce const nonce = crypto.randomBytes(16).toString('base64');
// Add to CSP header
script-src 'nonce-${nonce}'
// Add to script tags ...
For Next.js:
- Use middleware to generate nonce
- Pass nonce to pages via headers
- Apply to Script components
Show complete implementation for my framework.
CSP Violation Reporting
Set up CSP violation reporting to monitor issues.
Add reporting directives: report-uri /api/csp-report report-to csp-endpoint
Create report endpoint:
- Receive POST with JSON body
- Log violation details
- Filter noise (browser extensions, false positives)
- Alert on new/significant violations
Report payload includes:
- document-uri: page where violation occurred
- violated-directive: which rule was broken
- blocked-uri: what was blocked
- source-file: file containing violation
Use Report-Only header during development: Content-Security-Policy-Report-Only: ...
This reports violations without blocking, so you can build your policy without breaking the site.
Consider using a service like report-uri.com for aggregation.
Pro tip: Use browser DevTools console to see CSP violations in real-time. Each blocked resource shows what directive blocked it and why.
CSP is breaking my site. What do I do?
Use Report-Only mode first. Check browser console for violations. Add necessary sources one at a time. Avoid 'unsafe-inline' and 'unsafe-eval' if possible - use nonces or refactor code instead.
Does CSP replace XSS prevention?
No, CSP is defense in depth. You still need to properly escape output and sanitize input. CSP is a safety net that limits damage if XSS gets through, not a replacement for secure coding.