All posts
·5 min read·security headers · content security policy · cms

The Content Security Policy your CMS hides from you

Most CMS platforms ship without a Content Security Policy header, leaving your site exposed to XSS by default. Learn what CSP controls and how to add one.

Your CMS handles routing, templates, caching, and a dozen other concerns without your input. But there is one HTTP header most platforms deliberately leave blank: Content-Security-Policy. If you have never manually configured a CSP for your site, you almost certainly do not have one.

What Content Security Policy does

Content Security Policy (CSP) is an HTTP response header that tells browsers which sources of content are allowed to load on a page. You define rules for scripts, stylesheets, images, fonts, frames, and form submission targets. Each resource type can be restricted to specific domains, protocols, or cryptographic nonces.

When a browser receives a valid CSP header, it refuses to load anything that violates the policy. A script tag injected by an attacker pointing to a malicious domain? The browser blocks it. An inline event handler planted through an XSS vulnerability? Blocked before it runs.

The MDN Web Docs describe CSP as the primary browser-side defense against cross-site scripting, and that description holds up.

Why your CMS does not set one

WordPress, Squarespace, Wix, Webflow, Shopify, and HubSpot CMS share a common default: none of them ship a Content Security Policy header.

The reason is practical. A strict CSP breaks third-party scripts. Google Analytics, Facebook Pixel, Hotjar, chat widgets, embedded YouTube players, and Google Fonts all load resources from external domains. A CMS that enforces a strict policy out of the box would break most of those integrations for most users on day one.

So CMS platforms skip it entirely. Some set lighter headers like X-Content-Type-Options: nosniff or X-Frame-Options, but CSP gets left to you. In practice, "left to you" means "never configured." Most site owners do not know the header exists. Most agencies building on these platforms never add one either.

What that leaves exposed

Without CSP, your site implicitly trusts every domain on the internet to load and execute scripts in your visitors' browsers. That is the default browser behavior.

XSS attacks run unchecked. If an attacker injects a script through a vulnerable plugin, an unsanitized form field, or a compromised third-party dependency, the browser executes it. A configured CSP would block it at the browser level.

Sensitive data gets exfiltrated. A common XSS payload collects form data (credit card numbers, login credentials, personal information) and sends it to an external server. CSP's script-src and connect-src directives prevent that request from completing.

Cryptojacking scripts load freely. Injected cryptocurrency miners that run in your visitors' browsers are a real and ongoing problem, especially on sites with outdated CMS plugins. CSP blocks the miner when its source domain is not in the allowlist.

Clickjacking goes unblocked. The older X-Frame-Options header partially addresses framing attacks, but CSP's frame-ancestors directive gives you finer control over which domains can embed your pages.

Google's web.dev documentation classifies CSP as a primary mitigation for injection attacks.

Checking your current headers

Open your browser's developer tools (Network tab), load your homepage, and click the initial document request. Look for a Content-Security-Policy header in the response.

No header means no policy. If you see Content-Security-Policy-Report-Only, you have a policy in monitor-only mode that logs violations but blocks nothing.

Check the other security headers while you are there. HSTS, X-Frame-Options, Permissions-Policy, and Referrer-Policy all contribute to your site's security posture. A missing CSP is rarely the only gap.

Building a Content Security Policy for your CMS

Start in report-only mode. Set the Content-Security-Policy-Report-Only header with a restrictive baseline and a report-uri endpoint. This logs every resource that would be blocked without actually blocking anything.

A minimal starting policy:

Content-Security-Policy-Report-Only: default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self'; connect-src 'self'; frame-ancestors 'self'; report-uri /csp-report

This allows resources only from your own origin. Every third-party script, font, and image generates a violation report. Run it for a week or two, then add legitimate sources to the allowlist based on what the reports show.

Adding third-party sources. For each service you use, add its domains to the relevant directive. Google Analytics needs entries in script-src and connect-src. Google Fonts needs entries in style-src and font-src. Be specific: use https://www.googletagmanager.com rather than a wildcard like https://*.google.com.

Avoid unsafe-inline for scripts. This directive disables most of CSP's XSS protection. If your CMS or theme relies on inline scripts, use nonces or hashes to approve specific blocks without opening the door to all of them.

Where to set the header. On WordPress, a security plugin or a snippet in your server config (Nginx, Apache, or Cloudflare) can add it. On Netlify or Vercel, use the _headers file or vercel.json. On Cloudflare Pages, use _headers. On traditional hosting, add it to .htaccess or nginx.conf.

Once your violation reports stop showing false positives, switch from Content-Security-Policy-Report-Only to the enforced Content-Security-Policy header.

Find out what you are missing

Manual header checks cover one page at a time and require you to know exactly which headers to look for. The AcuityScan HTTP Headers tool parses your full response header set and flags missing security headers, including CSP, HSTS, Permissions-Policy, and X-Frame-Options. If HSTS is also absent, verify that your SSL configuration is solid first, since HSTS requires a valid certificate to function.

For a complete picture across security, performance, accessibility, and email authentication, run a full scan at acuityscan.com. It covers 350+ checks across 8 modules and returns specific findings with plain-English fix recommendations.

TL;DR

  • Content Security Policy is the strongest browser-side defense against XSS. Most CMS platforms ship without it.
  • Your CMS skips CSP because a strict policy would break third-party integrations. The result: every visitor is exposed to script injection by default.
  • Start with Content-Security-Policy-Report-Only to log violations without breaking your site.
  • Add legitimate third-party domains to your allowlist based on real violation reports.
  • Avoid unsafe-inline for scripts. Use nonces or hashes instead.
  • Switch from report-only to enforced once violation reports are clean.

Scan your own site

See what 350+ checks find on your domain.

Free, no signup, 60 seconds. Email auth · DNS · SSL · Performance · SEO · Accessibility · Privacy · Mobile.