---
title: Content Security Policy (CSP)
canonical: https://wpsecurityninja.com/docs/security-fixes/content-security-policy/
---
Content Security Policy (CSP) is an HTTP response header that tells browsers which sources may load scripts, styles, images, frames, and other assets. Used carefully, it limits what injected code can do. Used carelessly, it breaks Analytics, fonts, embeds, and the WordPress admin.

Security Ninja Pro can set related headers from **Security Ninja → Fixes**. Prefer report-only mode while you tune a policy. See also [Security headers](https://wpsecurityninja.com/docs/security-fixes/security-headers/).

## Why WordPress sites use CSP

A typical WordPress page loads assets from the theme, plugins, CDNs, fonts, and analytics. Without CSP, the browser will run injected JavaScript the same way it runs legitimate scripts. CSP cannot fix every plugin hole, but it raises the bar after injection.

## How CSP works

A basic policy:

```text
Content-Security-Policy: script-src 'self'
```

That allows scripts only from your own origin. External or injected scripts are blocked (or reported, in report-only mode).

## Useful directives

<dl class="docs-term-list">
<dt><code>default-src</code></dt>
<dd>Fallback for resource types you did not list</dd>
<dt><code>script-src</code></dt>
<dd>Allowed JavaScript sources</dd>
<dt><code>style-src</code></dt>
<dd>Allowed CSS sources</dd>
<dt><code>img-src</code></dt>
<dd>Allowed image sources</dd>
<dt><code>font-src</code></dt>
<dd>Allowed font sources</dd>
<dt><code>connect-src</code></dt>
<dd>AJAX, fetch, WebSocket, EventSource</dd>
<dt><code>frame-src</code></dt>
<dd>Embedded frames (YouTube, maps, payment widgets)</dd>
<dt><code>object-src</code></dt>
<dd>Plugins such as Flash; usually <code>'none'</code></dd>
<dt><code>form-action</code></dt>
<dd>Allowed form submission targets</dd>
<dt><code>frame-ancestors</code></dt>
<dd>Who may embed your pages (clickjacking related)</dd>
<dt><code>report-uri</code> / reporting APIs</dt>
<dd>Where browsers send violation reports</dd>
</dl>

## Example policies

**HTTPS-only baseline (weak XSS control):**

```text
Content-Security-Policy: default-src https:
```

**Common CDN allowlist (still often needs tuning):**

```text
Content-Security-Policy: default-src 'self'; script-src 'self' https://cdn.jsdelivr.net https://cdnjs.cloudflare.com; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' data:;
```

**Strict starting point (will break many WordPress sites until you add sources):**

```text
Content-Security-Policy: default-src 'none'; script-src 'self'; style-src 'self'; img-src 'self'; font-src 'self'; connect-src 'self'; frame-ancestors 'none'; base-uri 'self'; form-action 'self';
```

## Keywords

<dl class="docs-term-list">
<dt><code>'none'</code></dt>
<dd>Block all of that type</dd>
<dt><code>'self'</code></dt>
<dd>Same origin (not every subdomain)</dd>
<dt><code>'unsafe-inline'</code></dt>
<dd>Allows inline script/style; weakens CSP</dd>
<dt><code>'unsafe-eval'</code></dt>
<dd>Allows <code>eval()</code>-style APIs; weakens CSP</dd>
</dl>

Prefer nonces or hashes over `'unsafe-inline'` when you can. Many WordPress plugins still need temporary exceptions.

## Test before you enforce

Use report-only mode first:

```text
Content-Security-Policy-Report-Only: default-src 'self'; report-uri https://yoursite.com/csp-report
```

You can send an enforcing header and a report-only header at the same time while you trial a stricter policy. Do not trust violation report payloads blindly; rate-limit any endpoint that accepts them.

## WordPress-specific issues

* **Inline scripts and styles** in themes and plugins often need `'unsafe-inline'`, nonces, or refactoring.
* **Third-party services** (Analytics, fonts, chat, ads) each need explicit allowlist entries.
* **wp-admin** uses many inline scripts. Consider a looser policy for admin URLs than for the public site.
* **YouTube / maps embeds** need `frame-src` (and sometimes Referrer-Policy adjustments). See [YouTube Error 153](https://wpsecurityninja.com/docs/errors-and-debugging/troubleshooting-youtube-embed-issues-error-153/).

Example allowlist fragments:

```text
script-src https://www.google-analytics.com
font-src https://fonts.gstatic.com
style-src https://fonts.googleapis.com
frame-src https://www.youtube.com
```

## How to add the header

**Apache (`.htaccess`):**

```apache
Header set Content-Security-Policy "default-src 'self';"
```

**Theme or small plugin:**

```php
add_action(
	'send_headers',
	function () {
		header( "Content-Security-Policy: default-src 'self';" );
	}
);
```

**Security Ninja Pro:** enable and tune CSP-related options under **Security Ninja → Fixes**.

## Practical checklist

1. Start in report-only mode.
2. Watch the browser console and violation reports.
3. Add only the sources you need.
4. Avoid broad wildcards such as `https://*`.
5. Include `data:` in `img-src` if your theme uses data URIs.
6. Retest after installing or updating plugins.
7. Keep CSP as one layer. Updates, strong auth, and the firewall still matter.

## Further reading

* [Scott Helme’s CSP introduction](https://scotthelme.co.uk/content-security-policy-an-introduction/)
* [Security headers in Security Ninja](https://wpsecurityninja.com/docs/security-fixes/security-headers/)
