The nonce and strict-dynamic approach

Host allowlists are hard to get right: an allowed CDN or analytics host often serves a JSONP endpoint or an old library that runs whatever an attacker asks. A strict policy instead allows a script only when it carries a nonce generated for this response (or matches a hash), and lets those trusted scripts load their own dependencies.

ConfigurationHTTP
Content-Security-Policy: script-src 'nonce-{RANDOM}' 'strict-dynamic' https: 'unsafe-inline'; object-src 'none'; base-uri 'none'; frame-ancestors 'none'; report-to csp
Reporting-Endpoints: csp="https://example.com/csp-reports"
  • Generate a new random nonce of at least 128 bits for every response, and put it in the policy and in the nonce attribute of each <script> element you serve.
  • 'strict-dynamic' lets a script that carries the nonce load further scripts with document.createElement('script'), so you do not have to list every host. Scripts written with document.write or injected into HTML do not inherit that trust.
  • Browsers that support nonces ignore 'unsafe-inline', and browsers that support 'strict-dynamic' also ignore https:. Both are there only for old browsers, which then fall back to a weaker policy rather than breaking.
  • object-src 'none' blocks plugin content. base-uri 'none' stops an injected <base> element from redirecting relative script URLs; base-uri never falls back to default-src, so it must be set explicitly.
  • report-to csp names an endpoint in the Reporting-Endpoints header, for example Reporting-Endpoints: csp="https://example.com/csp-reports". Deploy it as Content-Security-Policy-Report-Only first, read the reports, then enforce.

How default-src fallback works

A request is checked against the most specific directive the policy contains, following the CSP Level 3 fallback list below. base-uri, form-action, frame-ancestors and sandbox never fall back to default-src, so a policy of only default-src 'none' still leaves them open.

CSP Level 3 directive fallback lists
DirectiveFalls back to, in order
script-src-elemscript-src → default-src
script-src-attrscript-src → default-src
style-src-elemstyle-src → default-src
style-src-attrstyle-src → default-src
worker-srcchild-src → script-src → default-src
connect-srcdefault-src
manifest-srcdefault-src
object-srcdefault-src
frame-srcchild-src → default-src
media-srcdefault-src
font-srcdefault-src
img-srcdefault-src