A Content-Security-Policy is an allowlist the browser enforces over what a page may load and run, and it is the single strongest browser-side defence against cross-site scripting and clickjacking. The policy is a list of directives, each naming a resource type and the sources permitted for it. This reference catalogues every directive by category along with the source-list keywords you combine to build a policy.
How it works
A CSP is delivered in the Content-Security-Policy response header (or a meta tag) as semicolon-separated directives. Fetch directives (script-src, style-src, img-src, connect-src, …) govern where each resource type may load from and fall back to default-src when unset. Document directives (base-uri, sandbox) and navigation directives (form-action, frame-ancestors) constrain the document itself and where it may go — these do not fall back. Reporting directives (report-to, report-uri) send violation reports.
Each directive takes a source list of keywords and origins. The keyword 'self' means the page’s own origin, 'none' blocks everything, and a 'nonce-<value>' or 'sha256-<hash>' allows a specific inline block. 'strict-dynamic' propagates trust from a nonced script to scripts it loads, letting you drop fragile host allowlists.
A strong baseline policy
default-src 'self';
script-src 'self' 'nonce-RANDOM' 'strict-dynamic';
object-src 'none';
base-uri 'self';
frame-ancestors 'none';
form-action 'self';
upgrade-insecure-requests;
report-to csp-endpoint
This policy says: load everything from your own origin by default; allow scripts only from the same origin or carrying the correct nonce, and trust those scripts to load their own dependencies; block plugins entirely; prevent base-tag hijacking; prevent framing by any origin; restrict form submissions to the same site; and upgrade all mixed content. Violations are sent to the reporting endpoint so you can catch breakage before users do.
The nonce pattern in practice
Every server response generates a fresh cryptographic random value (the nonce)
and places it in two locations: the script-src directive and the nonce
attribute on every inline <script> tag the server legitimately emits. An
attacker who injects a <script> block via XSS cannot know the nonce generated
for that response, so the injected script is blocked even though inline scripts
from the server are allowed. This model lets you eliminate 'unsafe-inline'
entirely without rewriting your application to remove all inline scripts — as
long as your server generates the nonce, not a build tool that bakes it in.
Common mistakes and how to avoid them
- Using
'unsafe-inline'as a workaround: Adding'unsafe-inline'toscript-srcdefeats the primary purpose of CSP. If you have inline scripts you cannot move to external files, use nonces or hashes instead. - Omitting
object-src: Flash and other plugins are controlled byobject-src, notdefault-srcfallback. Always setobject-src 'none'explicitly to block plugin-based attacks. - Forgetting
base-uri: An attacker who can inject a<base>tag can redirect all relative URLs. Setbase-uri 'self'orbase-uri 'none'. - Setting
frame-ancestorsonly in the meta tag: The meta tag does not supportframe-ancestors— it must be in the HTTP response header to prevent clickjacking. - Not testing with Report-Only first: Enforce too early and you break your
own site. Use
Content-Security-Policy-Report-Onlywithreport-tofor at least a week before switching to enforcement.
Avoid 'unsafe-inline' and 'unsafe-eval' in script-src
These keywords re-open the XSS hole CSP is meant to close. Roll out new policies
with the Content-Security-Policy-Report-Only header first so you can collect
violations via report-to and fix legitimate breakage before switching to
enforcement.