ProbeHunt

Add a Content-Security-Policy

Web headers · about 1 hour

In plain words

A CSP is an allow-list of where your pages may load scripts, styles and images from. If an attacker manages to inject a script, the browser refuses to run it.

What can go wrong

Without a CSP (or with 'unsafe-inline' / 'unsafe-eval' / wildcards), a single injection bug becomes account takeover, card skimming or defacement.

How to fix it

Pick the platform your site runs on. Not sure? Forward this page to whoever manages your website.

Nginx

# inside the server { } block
add_header Content-Security-Policy-Report-Only "default-src 'self'; img-src 'self' data:; script-src 'self'; style-src 'self' 'unsafe-inline'; frame-ancestors 'none'; base-uri 'self'; form-action 'self'" always;

Apache / .htaccess

<IfModule mod_headers.c>
  Header always set Content-Security-Policy-Report-Only "default-src 'self'; img-src 'self' data:; script-src 'self'; style-src 'self' 'unsafe-inline'; frame-ancestors 'none'; base-uri 'self'; form-action 'self'"
</IfModule>

Cloudflare

Rules → Transform Rules → Modify Response Header
  Set static: Content-Security-Policy-Report-Only = default-src 'self'; img-src 'self' data:; script-src 'self'; style-src 'self' 'unsafe-inline'; frame-ancestors 'none'; base-uri 'self'; form-action 'self'

# Cloudflare Pages: add to public/_headers
/*
  Content-Security-Policy-Report-Only: default-src 'self'; img-src 'self' data:; script-src 'self'; style-src 'self' 'unsafe-inline'; frame-ancestors 'none'; base-uri 'self'; form-action 'self'

Vercel

// vercel.json
{ "headers": [ { "source": "/(.*)", "headers": [
  { "key": "Content-Security-Policy-Report-Only", "value": "default-src 'self'; img-src 'self' data:; script-src 'self'; style-src 'self' 'unsafe-inline'; frame-ancestors 'none'; base-uri 'self'; form-action 'self'" }
] } ] }

Netlify

# public/_headers
/*
  Content-Security-Policy-Report-Only: default-src 'self'; img-src 'self' data:; script-src 'self'; style-src 'self' 'unsafe-inline'; frame-ancestors 'none'; base-uri 'self'; form-action 'self'

WordPress

// functions.php (child theme) — or use your security plugin's "HTTP headers" setting
add_action('send_headers', function () {
  header('Content-Security-Policy-Report-Only: default-src \'self\'; img-src \'self\' data:; script-src \'self\'; style-src \'self\' \'unsafe-inline\'; frame-ancestors \'none\'; base-uri \'self\'; form-action \'self\'');
});
Before you change anything: Start with Content-Security-Policy-Report-Only (shown above) and watch the browser console for a few days. Add the domains your site really needs (analytics, payment, fonts), then rename the header to Content-Security-Policy. For scripts, prefer nonces or hashes over 'unsafe-inline'.

Check that it worked

Re-run the ProbeHunt check — it flags a missing CSP and permissive script-src values.

Re-run the free check

References