Skip to main content

Free Tool

Content Security Policy (CSP) Checker

Enter any URL to instantly validate its Content-Security-Policy header. See which directives are missing, which values are dangerously permissive, and how to fix them — in seconds, no account needed.

Sign in with Google or GitHub to run the scan. Your first scan is free — no credit card required.

ZeriFlow Data — 12,400+ sites analyzed

Only 36% of sites in our corpus have a Content-Security-Policy header. Of those that do, 71% include unsafe-inline in script-src — which completely negates XSS protection.

What is a Content Security Policy?

CSP is an HTTP response header that tells browsers which sources are allowed to load content — scripts, styles, images, fonts, iframes. It is the most effective client-side protection against XSS attacks. Without CSP, any JavaScript injected into your page by an attacker runs with full permissions in your visitors' browsers.

CSP works through directives. Each directive controls a specific content type:

default-src

Fallback for all content types not explicitly defined

script-src

Controls JavaScript sources

style-src

Controls CSS sources

img-src

Controls image sources

connect-src

Controls fetch/XHR/WebSocket connections

frame-ancestors

Controls who can embed your page (replaces X-Frame-Options)

object-src

Controls Flash/plugins — always set to 'none'

base-uri

Prevents base tag injection attacks

The Biggest CSP Mistakes

1. unsafe-inline in script-src

This keyword allows all inline scripts to execute — including any script an attacker injects via an XSS vulnerability. It completely negates XSS protection. Use nonces instead.

# BAD — negates XSS protection
Content-Security-Policy: script-src 'self' 'unsafe-inline'

# BETTER — use nonces
Content-Security-Policy: script-src 'self' 'nonce-r4nd0m'

2. unsafe-eval in script-src

Allows eval(), setTimeout(string), and new Function() — all XSS vectors. Never use this unless you have no alternative and have exhausted all other options.

3. Wildcard * in default-src

Allows loading from any origin. This is equivalent to having no CSP at all — an attacker can inject a script tag pointing to their server and the browser will execute it.

4. Missing object-src 'none'

Flash plugins — even if considered dead — can bypass script-src restrictions without this directive explicitly set to 'none'. Always include it.

5. No frame-ancestors

Without this directive, your site can still be iframed by attackers for clickjacking attacks. Set frame-ancestors 'none' if you never need to be embedded, or specify trusted origins explicitly.

How to Implement CSP Without Breaking Your Site

Start with report-only mode. Deploy the header below and collect violations for 1-2 weeks before enforcing anything:

Content-Security-Policy-Report-Only: default-src 'self'; report-uri /csp-report

Recommended progression once you switch to enforcement mode:

  1. 01

    Start with default-src 'self'

  2. 02

    Add nonces for inline scripts — remove unsafe-inline

  3. 03

    Restrict specific third-party domains (analytics, fonts, CDNs)

  4. 04

    Add frame-ancestors 'none' or a trusted origin allowlist

  5. 05

    Add object-src 'none' to block plugin execution

  6. 06

    Enable upgrade-insecure-requests to force HTTPS for subresources

CSP Examples by Framework

Nginx

add_header Content-Security-Policy
  "default-src 'self';
   script-src 'self' 'nonce-$request_id';
   object-src 'none';
   frame-ancestors 'none'"
  always;

Next.js (next.config.js)

// next.config.js
headers() {
  return [{
    source: '/(.*)',
    headers: [{
      key: 'Content-Security-Policy',
      value:
        "default-src 'self'; " +
        "script-src 'self' 'nonce-{n}'; " +
        "object-src 'none'; " +
        "frame-ancestors 'none'"
    }]
  }]
}

Express (helmet)

import helmet from 'helmet';
app.use(helmet.contentSecurityPolicy({
  directives: {
    defaultSrc: ["'self'"],
    scriptSrc: ["'self'"],
    objectSrc: ["'none'"],
    frameAncestors: ["'none'"],
  }
}));

Frequently Asked Questions

What does a Content-Security-Policy header do?

A Content-Security-Policy header tells the browser which sources are allowed to load scripts, styles, images, fonts, and other resources on your page. If a resource is not explicitly permitted, the browser refuses to load it. This makes it the most effective client-side defense against Cross-Site Scripting (XSS) attacks — an injected script from an unauthorized origin is simply blocked before it executes.

Why does my site break when I add CSP?

CSP breaks sites when inline scripts or styles are present without a nonce or hash, when external resources like Google Fonts, analytics scripts, or CDN-hosted libraries are not listed in the relevant directives, or when eval() is used by a JavaScript framework. The safest approach is to start with Content-Security-Policy-Report-Only mode, collect violation reports for 1-2 weeks, then tighten the policy incrementally.

What is the difference between CSP and CSP-Report-Only?

Content-Security-Policy actively blocks policy violations — the browser refuses to load non-compliant resources. Content-Security-Policy-Report-Only does nothing to the page but sends a violation report to the URI specified in the report-uri directive. Report-Only is the standard way to test a new policy in production without risking breakage.

Should I use 'unsafe-inline' in my CSP?

No. 'unsafe-inline' in script-src completely defeats XSS protection — it allows any inline script on the page to execute, including injected ones. The correct solution is nonce-based CSP: generate a cryptographically random nonce per request, add it to your script tags as a nonce attribute, and include 'nonce-{value}' in your script-src directive. Frameworks like Next.js support nonce injection via middleware.

How do I add a CSP nonce in Next.js?

In Next.js 13+, create a middleware.ts file at the project root. Generate a nonce with crypto.randomUUID() or the Web Crypto API, set it in a response header (e.g. x-nonce), then read it in your root layout to pass to the next.config.js headers() function and to your Script components via the nonce prop. The Next.js documentation has a complete example for App Router projects.

Ready to check your website?

Full security report — 80+ checks in 60 seconds.