How CSP is delivered

Via the Content-Security-Policy response header. A meta tag also works but is more limited (no frame-ancestors, can't apply to network responses).

Content-Security-Policy:
  default-src 'self';
  script-src 'self' 'nonce-rAnd0m';
  style-src 'self' 'unsafe-inline';
  img-src 'self' data: https:;
  font-src 'self' https://fonts.gstatic.com;
  connect-src 'self' https://api.example.com;
  frame-ancestors 'none';
  base-uri 'self';
  form-action 'self';
  upgrade-insecure-requests;

Core directives

DirectiveControls
default-srcFallback for fetch directives that aren't set.
script-srcJavaScript sources, inline scripts, and eval.
style-srcCSS sources and inline styles.
img-srcImage sources.
connect-srcfetch, XHR, WebSocket, EventSource targets.
font-srcFont sources.
frame-ancestorsWho can <iframe> this page (replaces X-Frame-Options).
base-uriPermissible values for <base> — prevents path hijacking.
form-actionWhere forms can be submitted.
object-srcPlugin content. Best set to 'none'.

Nonces vs hashes vs strict-dynamic

Roll it out safely

  1. Send Content-Security-Policy-Report-Only with your draft policy and a report-to endpoint.
  2. Watch the reports for a week. Tighten misses; identify legitimate sources you missed.
  3. When violations drop to zero, switch to the enforcing header.
  4. Keep collecting reports — a sudden spike usually means a new third-party script was added without coordination.
!

Avoid 'unsafe-inline' in script-src. It defeats most of CSP's XSS mitigation. Use nonces or hashes instead.