Fix Guide

How to Set Up a Content-Security-Policy in WordPress

February 8, 2026

Content-Security-Policy (CSP) is one of the most powerful security headers available, but it is also one of the trickiest to get right on WordPress. The reason is simple: WordPress core, themes, and plugins all love to use inline scripts and styles. A strict CSP blocks those by default, which means your site can break in unexpected ways if you do not plan carefully. This guide walks you through the entire process, from understanding what CSP does to deploying a production-ready policy.

Why CSP Is Especially Challenging on WordPress

Most WordPress sites rely heavily on patterns that CSP is designed to restrict. Here are the most common issues you will run into:

  • Inline scripts: many plugins inject JavaScript directly into the HTML using <script> tags without src attributes. Page builders like Elementor, WPBakery, and Divi do this extensively.
  • Inline styles: the WordPress Customizer, Gutenberg blocks, and most themes add style attributes or <style> blocks to the page. A strict CSP with no 'unsafe-inline' for styles will break the visual appearance of your site.
  • eval() usage: some plugins use JavaScript's eval() function or similar constructs, which requires the 'unsafe-eval' directive.
  • Third-party resources: Google Analytics, Google Fonts, reCAPTCHA, embedded YouTube videos, social media widgets. Each one needs its own CSP entry.

Because of all this, you should never copy a CSP from another website and paste it into your WordPress configuration. Every WordPress site has a unique combination of plugins and themes, so every CSP needs to be tailored individually.

Start with Report-Only Mode to Discover What Would Break

The safest way to begin is with the Content-Security-Policy-Report-Only header. This header behaves exactly like CSP, except it does not actually block anything. Instead, it logs violations in the browser console so you can see what your policy would prevent. Nothing on your site breaks, but you get full visibility.

Add this to your .htaccess file (Apache):

<IfModule mod_headers.c>
    Header set Content-Security-Policy-Report-Only "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' data: https://fonts.gstatic.com; connect-src 'self';"
</IfModule>

Or for Nginx:

add_header Content-Security-Policy-Report-Only "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' data: https://fonts.gstatic.com; connect-src 'self';" always;

Leave this running for at least a few days, and browse through all major pages of your site (home, blog posts, contact form, WooCommerce checkout if applicable). Each page may load different plugins and resources.

How to Find CSP Violations in the Browser Console

After enabling Report-Only mode, open your site in Chrome or Firefox and press F12 to open DevTools. Go to the Console tab. CSP violations appear as warning messages that look like this:

[Report Only] Refused to load the script 'https://www.googletagmanager.com/gtag/js' because it violates the following Content Security Policy directive: "script-src 'self' 'unsafe-inline'".

Each violation message tells you exactly what was blocked and which directive caused it. Collect all of these messages and use them to build your allowlist. Visit every important page on your site, including pages with forms, sliders, maps, and any page that loads unique plugins.

Understanding the Key CSP Directives for WordPress

Here are the directives you will most likely need to configure:

  • default-src: the fallback for all resource types not explicitly listed. Set this to 'self' as a baseline.
  • script-src: controls where JavaScript can be loaded from. You will almost certainly need 'unsafe-inline' on WordPress. If any plugin uses eval(), you also need 'unsafe-eval'.
  • style-src: controls where CSS can be loaded from. WordPress nearly always requires 'unsafe-inline' here.
  • img-src: controls image sources. Use 'self' data: https: to allow your own images, data URIs (used by many plugins), and any image over HTTPS.
  • font-src: controls font loading. If you use Google Fonts, add https://fonts.gstatic.com.
  • connect-src: controls where JavaScript can make network requests (AJAX, fetch, WebSocket). WordPress admin uses this heavily for the REST API and Heartbeat API.
  • frame-src: controls which domains can be loaded in iframes. Needed for YouTube embeds (https://www.youtube.com), Google Maps (https://www.google.com), and reCAPTCHA (https://www.google.com).
  • media-src: controls audio and video sources. Usually 'self' is sufficient unless you embed external media.
  • object-src: controls plugins like Flash. Set to 'none' since Flash is dead and this directive mostly prevents legacy attack vectors.

Building Your Policy Step by Step

Start with a restrictive baseline and add exceptions as you discover violations:

  1. Begin with a minimal policy: default-src 'self'; script-src 'self'; style-src 'self'; img-src 'self';
  2. Add unsafe-inline for scripts and styles: this is almost always necessary on WordPress. script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline';
  3. Add data: URIs for images and fonts: many plugins use base64-encoded images. img-src 'self' data: https:; font-src 'self' data:;
  4. Whitelist your CDN: if you use a CDN like Cloudflare or BunnyCDN, add its domain to script-src, style-src, img-src, and font-src.
  5. Add third-party services one by one: for each CSP violation in the console, add the specific domain to the matching directive.

Common Allowlist Entries for WordPress Sites

Here is a reference of domains you might need for popular WordPress integrations:

  • Google Fonts: style-src https://fonts.googleapis.com and font-src https://fonts.gstatic.com
  • Google Analytics / GA4: script-src https://www.googletagmanager.com https://www.google-analytics.com and connect-src https://www.google-analytics.com https://analytics.google.com
  • Google Maps: script-src https://maps.googleapis.com and frame-src https://www.google.com
  • YouTube embeds: frame-src https://www.youtube.com https://www.youtube-nocookie.com
  • reCAPTCHA: script-src https://www.google.com https://www.gstatic.com and frame-src https://www.google.com
  • Gravatar: img-src https://secure.gravatar.com https://www.gravatar.com
  • WordPress.org: img-src https://s.w.org https://ps.w.org (for plugin/theme icons in the admin)

A Complete WordPress CSP Example

Here is a realistic CSP for a WordPress site that uses Google Analytics, Google Fonts, YouTube embeds, and Gravatar. Adapt it to your specific needs:

<IfModule mod_headers.c>
    Header set Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' https://www.googletagmanager.com https://www.google-analytics.com; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; img-src 'self' data: https: https://secure.gravatar.com; font-src 'self' data: https://fonts.gstatic.com; connect-src 'self' https://www.google-analytics.com https://analytics.google.com; frame-src https://www.youtube.com https://www.youtube-nocookie.com; object-src 'none'; base-uri 'self'; form-action 'self';"
</IfModule>

WordPress Plugins for Managing CSP

If editing server config files feels intimidating, these plugins can help:

  • HTTP Headers: a free plugin that lets you define all security headers from the WordPress admin. It supports CSP with a user-friendly interface where you can add sources per directive.
  • Really Simple SSL Pro: includes a content security policy module with violation logging and one-click fixes for common issues.
  • Jeremykendall's CSP plugin: a lightweight option that focuses solely on CSP management.

Keep in mind that plugin-based CSP headers are only sent for pages processed by WordPress. Static resources served directly by your web server will not carry the header. For complete protection, server-level configuration is preferred.

Switching from Report-Only to Enforcing Mode

Once you have run in Report-Only mode for at least a week and resolved all violations, you are ready to switch. Simply change the header name from Content-Security-Policy-Report-Only to Content-Security-Policy. Keep your browser console open during the first few hours and monitor for any violations you might have missed. If something breaks, you can always switch back to Report-Only while you fix it.

Verify Your CSP with InspectWP

After implementing your Content-Security-Policy, run a new InspectWP scan. The security headers section of your report will show whether a CSP header is present and whether it is in Report-Only or enforcing mode. Use this as a quick check after any changes to confirm your policy is still being sent correctly.

Check your WordPress site now

InspectWP analyzes your WordPress site for security issues, SEO problems, GDPR compliance, and performance — for free.

Analyze your site free