How it works
The server sends a Content-Security-Policy header that lists the allowed sources for each type of content: script-src for JavaScript, style-src for CSS, img-src for images, connect-src for fetch calls, frame-ancestors for who may embed the page (the modern defence against clickjacking), and so on. The browser blocks anything that does not match and can report violations to an address you choose.
The strongest setup is a strict policy based on nonces or hashes: each response gets a fresh random nonce, only script tags carrying it may run, and inline scripts an attacker injects are refused. Allow-lists of whole domains are weaker, because a permitted domain may host scripts an attacker can reuse, and 'unsafe-inline' switches off most of the protection. Third-party widgets need their origins allowed; Turnstile, for example, needs challenges.cloudflare.com.
Rolling a policy out with the Content-Security-Policy-Report-Only header first shows what would break without blocking anything. CSP can also be set in a meta tag, although a few directives such as frame-ancestors only work as a header. It is a safety net for XSS, not a replacement for escaping output.
Related terms
More in Security
Defences