How to fix a missing Content-Security-Policy (CSP) header | Scanthra
May 2026What is the Content-Security-Policy header?
CSP is a response header that tells the browser exactly which sources of scripts, styles, images and frames it is allowed to load. If something on the page tries to load a script from a domain that isn't on your allow-list, the browser refuses. It's like a guest list for the bouncer at the door.
Without CSP, any injected <script> tag — from a hacked
plugin, a typo in a third-party widget, a stored XSS in a comment — runs
with full access to your visitors' cookies, form data and session. With a
strict CSP, the same injection is silently blocked and logged.
Why this matters for a small business
Two real-world examples we see weekly in Scanthra reports:
- Card skimming on checkouts — a compromised JavaScript library on a WooCommerce shop reads card numbers and exfiltrates them. With CSP, that exfiltration request to an attacker domain is blocked.
- Defacement and phishing overlays — an injected script swaps your contact form for one that emails the attacker. CSP would refuse to load the unknown script in the first place.
CSP is also explicitly recommended by OWASP, expected by most cyber insurance questionnaires, and — for EU businesses — a sensible part of the "appropriate technical measures" required by GDPR Article 32 and the NIS2 Directive.
The safe rollout: report-only mode first
The biggest reason small sites avoid CSP is fear of breaking the layout.
The fix: deploy Content-Security-Policy-Report-Only first. The
browser checks the policy and reports violations, but doesn't
enforce them. Watch the logs for a week, fix what's blocked, then flip to
the enforcing header.
A starter policy that works for most sites
Content-Security-Policy-Report-Only:
default-src 'self';
script-src 'self' https://www.googletagmanager.com https://www.google-analytics.com;
style-src 'self' 'unsafe-inline' https://fonts.googleapis.com;
font-src 'self' https://fonts.gstatic.com;
img-src 'self' data: https:;
connect-src 'self' https://www.google-analytics.com;
frame-ancestors 'none';
base-uri 'self';
form-action 'self';
upgrade-insecure-requests
This policy assumes you serve everything from your own domain plus Google Analytics + Google Fonts. Almost every WordPress, Shopify or static site fits in here with small tweaks. Replace or remove the GA/Fonts lines if you don't use them.
How to deploy on nginx
add_header Content-Security-Policy-Report-Only "default-src 'self'; script-src 'self' https://www.googletagmanager.com; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; img-src 'self' data: https:; frame-ancestors 'none'; base-uri 'self'; form-action 'self'; upgrade-insecure-requests" always;
How to deploy on Apache
Header always set Content-Security-Policy-Report-Only "default-src 'self'; script-src 'self' https://www.googletagmanager.com; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; img-src 'self' data: https:; frame-ancestors 'none'; base-uri 'self'; form-action 'self'; upgrade-insecure-requests"
How to deploy on Cloudflare
In your Cloudflare dashboard go to Rules → Transform Rules → HTTP
Response Header Modification. Add a header named
Content-Security-Policy-Report-Only with the policy above as
the value. This is the fastest option if you don't have shell access to
your server.
How to deploy on WordPress
Install a header plugin such as Headers Security Advanced &
HSTS WP or add the headers via your hosting panel. Avoid setting CSP
inside a theme's functions.php — many themes load
WP-admin or block editor assets dynamically and that breaks the editor
experience.
Common pitfalls
- Inline scripts. If your CMS injects inline
<script>tags, you'll see violations. The fix is either nonces (best) or, as a temporary measure,script-src 'self' 'unsafe-inline'— but plan to remove'unsafe-inline'within a sprint. - Google Tag Manager. GTM loads other scripts at runtime from third-party hosts. Either pre-declare those hosts in your policy or use GTM's built-in Custom Templates with a nonce strategy.
- Embedded YouTube / Vimeo. Add
frame-src https://www.youtube.com https://player.vimeo.com. - Reporting endpoint. Add
report-uri /csp-reportorreport-toso you capture violations server-side. Some hosts (Cloudflare, Sentry) offer free CSP report endpoints.
From report-only to enforcing
After a week of report-only with no new violations on real traffic, rename
the header from Content-Security-Policy-Report-Only to
Content-Security-Policy. The policy is now enforced. Keep
the reporting endpoint — you'll catch new violations the moment a plugin
update introduces an unexpected script.
How Scanthra detects this
Our Security Headers module makes a single GET to your homepage
and reads the response headers. If Content-Security-Policy
is missing, weak, or contains unsafe-eval, you'll get a
finding with severity, plain-English description and a copy-paste fix —
same format as in this article.
Want to know if your site has this issue?
Scanthra runs a friendly, passive check and emails you a plain-English PDF report.
Scan your site free