BCDRPulse

Security Headers Checker / Headers

Content-Security-Policy (CSP): what it does and a safe way to add it

CSP tells the browser which sources may provide scripts, styles, images, frames and connections for the page. A script an attacker injects into the page does not run if the policy does not allow its source, which makes CSP the main defence against cross-site scripting.

What to send

Content-Security-Policy-Report-Only: default-src 'self'; object-src 'none'; base-uri 'self'; frame-ancestors 'self'; form-action 'self'; upgrade-insecure-requests

Start in Report-Only: it blocks nothing and reports what an enforced policy would block. Add the sources your pages really use, then switch the header name to Content-Security-Policy. A strict policy uses nonces or hashes with 'strict-dynamic' instead of host allowlists.

# server { } block (or a file included in every server block).
# "always" also sends the header on error and redirect responses.
add_header Content-Security-Policy-Report-Only "default-src 'self'; object-src 'none'; base-uri 'self'; frame-ancestors 'self'; form-action 'self'; upgrade-insecure-requests" always;

Will this break anything?

  • Content-Security-Policy-Report-Only blocks nothing: browsers only report what an enforced policy would block, so it is safe to add first and watch.

How our grade counts it

  • Coverage, up to 25 points: 10 for any enforced policy; 15 when scripts are restricted (no effective 'unsafe-inline', no wildcard or scheme-only sources); 20 / 23 / 25 for the strict levels L1 / L2 / L3 (nonce or hash with 'strict-dynamic' and 'unsafe-eval' / without 'unsafe-eval' / nonce- or hash-only)
  • Effectiveness, minus 10: CSP allows 'unsafe-eval' (not charged on a strict policy at level L1, whose 20 points instead of 23 are that charge)
  • Effectiveness, minus 10: An enforced CSP allowlists a host with a known bypass (JSONP, AngularJS, Flash)
  • Effectiveness, minus 5: CSP has neither object-src nor default-src
  • Effectiveness, minus 5: CSP uses nonces or hashes without base-uri

The full grading rules

Common mistakes

  • 'unsafe-inline' in script-src without a nonce or hash: inline scripts, including injected ones, run.
  • Allowlisting whole CDNs (https:, *.googleapis.com, cdnjs): they host libraries that can be abused to bypass the policy.
  • frame-ancestors, report-uri and sandbox in a <meta> tag: browsers ignore them there; send them as a header.
  • A policy only in Report-Only forever: it protects nothing.

Check your site

The checker reads Content-Security-Policy the way a browser applies it, alongside every other security header.

Open the Security Headers Checker

Content-Security-Policy on MDN