By header

A Content-Security-Policy That Won't Break Your Site (Starter)

5 min read

Content-Security-Policy (CSP) is the highest-impact header against XSS — and the easiest to break your own site with. The trick: start in report-only mode, see what it would block, then enforce.

Step 1 — report-only (breaks nothing)

This header logs violations but does NOT block anything. Ship it first:

Content-Security-Policy-Report-Only: default-src 'self'; img-src 'self' data:; style-src 'self'; script-src 'self'; object-src 'none'; base-uri 'self'; frame-ancestors 'self'

Open your site, watch the browser console for “would have been blocked” messages, and add the sources you actually need.

Step 2 — enforce

Once report-only is clean, rename the header to enforce it:

Content-Security-Policy: default-src 'self'; img-src 'self' data:; style-src 'self'; script-src 'self'; object-src 'none'; base-uri 'self'; frame-ancestors 'self'

Per server (enforcing form)

Nginx:

add_header Content-Security-Policy "default-src 'self'; img-src 'self' data:; style-src 'self'; script-src 'self'; object-src 'none'; base-uri 'self'; frame-ancestors 'self'" always;

Apache:

Header always set Content-Security-Policy "default-src 'self'; img-src 'self' data:; style-src 'self'; script-src 'self'; object-src 'none'; base-uri 'self'; frame-ancestors 'self'"

Caddy:

header Content-Security-Policy "default-src 'self'; img-src 'self' data:; style-src 'self'; script-src 'self'; object-src 'none'; base-uri 'self'; frame-ancestors 'self'"

_headers:

/*
  Content-Security-Policy: default-src 'self'; img-src 'self' data:; style-src 'self'; script-src 'self'; object-src 'none'; base-uri 'self'; frame-ancestors 'self'

Inline scripts/styles

'self' blocks inline <script> and style="". If you can’t remove them, prefer a nonce or hash over 'unsafe-inline':

script-src 'self' 'nonce-RANDOM_PER_REQUEST'

Generate a fresh random nonce on each response and put the same value in the tag’s nonce attribute. Avoid 'unsafe-inline' for script-src — it defeats most of CSP’s XSS protection.

Verify

curl -sI https://yourdomain.com | grep -i content-security-policy

Common additions: font-src 'self' data:, connect-src 'self' https://api.example.com (for fetch/XHR/WebSocket), frame-src for embeds. Add only what your site actually loads, and keep object-src 'none' and base-uri 'self' — they’re cheap, high-value defenses.

Open the full version (with copy buttons) ↗

← All recipes