Guides / Content-Security-Policy

Security Header Guide

How to Add a Content-Security-Policy Header — Beginner’s Guide

Content-Security-Policy (CSP) is one of the most powerful browser security headers — and one of the most commonly missing. This guide explains exactly what it does and how to safely add it to your site, even if you’ve never set one before.

What is a Content-Security-Policy?

CSP is an HTTP response header that tells the browser exactly which sources of scripts, styles, images, fonts, and other resources are allowed to load on your page. Any resource not matching your policy is blocked before it executes.

Without a CSP, if an attacker manages to inject a <script> tag into your page (via a stored XSS vulnerability, a compromised third-party script, or a browser extension injecting content), it runs with the same trust as your own code — accessing cookies, session tokens, user keystrokes, and any data on the page.

CSP is your last line of defense against Cross-Site Scripting (XSS), one of OWASP’s Top 10 vulnerabilities and a common way attackers steal session tokens and user data.

Understanding CSP Directives

A CSP header value is a semicolon-separated list of directives. Each directive controls a different resource type:

DirectiveControls
default-srcFallback for all resource types not explicitly listed
script-srcJavaScript files and inline <script> blocks
style-srcCSS files and inline <style> blocks
img-srcImages (including data: URIs)
font-srcWeb fonts (woff, woff2, ttf, etc.)
connect-srcfetch(), XMLHttpRequest, WebSocket connections
frame-ancestorsWhich pages may embed this page in an iframe (replaces X-Frame-Options)
base-uriAllowed values for the <base> element

A Safe Starter CSP Policy

The policy below is a solid starting point for most websites that load resources only from their own domain plus Google Fonts and a CDN like jsDelivr:

Content-Security-Policy:
  default-src 'self';
  script-src 'self' 'nonce-RANDOM_NONCE';
  style-src 'self' 'unsafe-inline' https://fonts.googleapis.com;
  font-src 'self' https://fonts.gstatic.com;
  img-src 'self' data: https:;
  connect-src 'self';
  frame-ancestors 'none';
  base-uri 'self';
  form-action 'self';

Replace RANDOM_NONCE with a per-request random value if you use inline scripts; alternatively use 'sha256-…' hashes. If your site currently uses a lot of inline scripts, you can temporarily add 'unsafe-inline' to script-src to avoid breakage while you audit.

Test before enforcing: Start with Content-Security-Policy-Report-Only instead of Content-Security-Policy. This logs violations to DevTools (or a report-uri endpoint) without blocking anything, letting you refine your policy before locking it down.

How to Add CSP on Nginx

Add the header in your HTTPS server block:

server {
    listen 443 ssl;
    server_name example.com;

    add_header Content-Security-Policy
        "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; font-src 'self' https://fonts.gstatic.com; img-src 'self' data: https:; connect-src 'self'; frame-ancestors 'none';"
        always;
}

Long policies should be kept on one line in Nginx config. After editing, test your config with sudo nginx -t before reloading.

How to Add CSP on Apache

Enable mod_headers if needed (sudo a2enmod headers), then add to your VirtualHost:

<VirtualHost *:443>
    ServerName example.com

    Header always set Content-Security-Policy         "default-src 'self'; script-src 'self';          style-src 'self' 'unsafe-inline' https://fonts.googleapis.com;          font-src 'self' https://fonts.gstatic.com;          img-src 'self' data: https:; connect-src 'self';          frame-ancestors 'none';"
</VirtualHost>

How to Add CSP on Cloudflare

Cloudflare can inject CSP headers via a Transform Rule:

  1. Go to your domain in the Cloudflare dashboard → Rules → Transform Rules → Modify Response Header.
  2. Click Create Rule. Set the Expression to true (applies to all requests).
  3. Under Then, choose Add → Header name: content-security-policy, Value: your full policy string.
  4. Click Deploy.

Alternatively, use a Cloudflare Worker to inject the header dynamically (useful if you need per-request nonces for inline scripts).

How to Verify Your CSP

Check the header is present with curl:

curl -sI https://example.com | grep -i content-security

Open Chrome DevTools → Console. Any blocked resource shows a CSP violation error with the exact directive that blocked it, making it easy to refine your policy:

Refused to load the script 'https://cdn.example.com/analytics.js'
because it violates the following Content Security Policy directive:
"script-src 'self'". Consider adding 'unsafe-inline' or a nonce...

Use the CSP Evaluator tool from Google (csp-evaluator.withgoogle.com) to score the strength of your policy and identify weaknesses.

Not sure if your site has a CSP header?

Run a free Vigilai scan to check CSP, HSTS, X-Frame-Options, TLS, and 4 other headers in seconds — no account needed.