HomeLibraryContent-Security-Policy recipes

Content-Security-Policy recipes

Copy-ready Content-Security-Policy header values for the setups people actually run: a strict starter, Google Fonts, analytics, YouTube embeds, nonce-based scripts, clickjacking protection. Click a card to copy the policy, then set it as the Content-Security-Policy header (each recipe notes what it allows). The strip on each card shows one block per directive, amber blocks contain an unsafe-* source worth revisiting.

Strict starter (same-origin only)
default-src 'self'; object-src 'none'; base-uri 'self'; frame-ancestors 'self'
Self + images from anywhere (https)
default-src 'self'; img-src 'self' data: https:; object-src 'none'; base-uri 'self'
SPA calling one API origin
default-src 'self'; connect-src 'self' https://api.example.com; img-src 'self' data:; object-src 'none'
Google Fonts
default-src 'self'; style-src 'self' https://fonts.googleapis.com; font-src 'self' https://fonts.gstatic.com; object-src 'none'
Google Analytics 4
default-src 'self'; script-src 'self' https://www.googletagmanager.com; connect-src 'self' https://*.google-analytics.com https://*.analytics.google.com; img-src 'self' https://*.google-analytics.com; object-src 'none'
YouTube embeds
default-src 'self'; frame-src https://www.youtube-nocookie.com https://www.youtube.com; img-src 'self' https://i.ytimg.com; object-src 'none'
Nonce + strict-dynamic scripts
script-src 'nonce-{RANDOM}' 'strict-dynamic'; object-src 'none'; base-uri 'none'
Pragmatic: inline styles allowed
default-src 'self'; style-src 'self' 'unsafe-inline'; object-src 'none'; base-uri 'self'
Upgrade http subresources to https
default-src 'self'; upgrade-insecure-requests
Clickjacking off (no framing)
frame-ancestors 'none'
Report-Only rollout starter
default-src 'self'; report-uri /csp-report; report-to csp-endpoint

FAQ

Where do I set a CSP?
Preferably as an HTTP response header: Content-Security-Policy: <value> in your server, CDN, or hosting config. A <meta http-equiv="Content-Security-Policy"> tag also works for most directives, but frame-ancestors, report-uri and report-to are header-only, so recipes using them must be set as headers.
How do I roll one out without breaking my site?
Start with the Content-Security-Policy-Report-Only header (the Report-Only recipe here): the browser reports violations without blocking anything. Watch the reports for a week, add the sources your site genuinely needs, then switch the same value to the enforcing header.
What does the nonce-{RANDOM} placeholder mean?
Replace {RANDOM} with a fresh base64 value generated per response, and put the same value in each script tag as nonce="…". Together with strict-dynamic this allows exactly the scripts you emitted (and what they load) while blocking everything injected, which is stronger than maintaining a host allowlist.
Why is 'unsafe-inline' marked amber?
Allowing inline code is the main hole XSS attacks use, an injected <script> or style attribute runs like your own. The style-src 'unsafe-inline' recipe exists because many frameworks still inject inline styles, but treat it as a stopgap: for scripts, prefer nonces or hashes instead, which is why no recipe here includes script-src 'unsafe-inline'.
Family Site