Skip to main content

CSP Header Generator

Build Content-Security-Policy headers with a visual form, presets and per-directive configuration.

Reviewed by · Last reviewed

Presets:

Using the CSP Header Generator

  1. Pick a preset - "Strict" locks everything to 'self' plus required nonces, "Moderate" adds https: sources and common analytics domains, "Report-Only" emits a Content-Security-Policy-Report-Only header that logs violations without blocking them.
  2. Adjust per-directive sources - each directive (default-src, script-src, style-src, img-src, connect-src, frame-src, font-src, media-src, worker-src) has a list of sources you can add or remove. Common values ('self', 'none', https:, data:, specific origins) appear as one-click adds.
  3. Add nonces or hashes - for inline scripts or styles you cannot refactor, add a nonce placeholder ('nonce-{RANDOM}') or a hash ('sha256-HASH') and remember to generate a fresh nonce per response server-side.
  4. Enable strict-dynamic - toggled on, it lets scripts loaded by trusted scripts also execute without listing every CDN origin individually. This is the modern CSP Level 3 approach.
  5. Copy the header - the output is a single-line Content-Security-Policy value. Paste into your web server config (Nginx add_header, Apache Header set, Cloudflare Workers, Netlify _headers, or a meta tag as last resort).

What CSP Actually Does

Content Security Policy is an HTTP response header specified in W3C CSP Level 3 (Working Draft, with Level 2 at Recommendation status). When the browser receives a page with a Content-Security-Policy header, it enforces a whitelist at resource-load time: script sources, style sources, image sources, frame ancestors, connect endpoints, and more. Violations trigger a SecurityPolicyViolationEvent in the page\'s DOM and optionally POST a violation report to the URL specified in report-uri (Level 2) or report-to (Level 3).

The security value is XSS mitigation. A well-configured CSP renders inline scripts (<script>alert(1)</script>) un-executable and blocks script loads from attacker-controlled domains, so even when a markup injection vulnerability exists, the attacker cannot execute JavaScript. The MDN CSP documentation and the W3C spec at w3.org/TR/CSP3/ document the directive grammar in detail; the trick is writing a policy that locks down untrusted content without breaking your own application.

Real CSP Deployment Scenarios

  • Hardening a marketing site against XSS from user-generated content (comments, testimonial widgets) - CSP is the last line of defense when input sanitization fails.
  • Meeting compliance requirements (PCI DSS 4.0 explicitly requires CSP for payment pages as of March 2025; SOC 2 checklists routinely include it).
  • Defending against supply-chain attacks on third-party scripts - with a strict script-src, a compromised NPM package served by a CDN cannot exfiltrate data to an attacker domain.
  • Blocking ad injection by ISPs or browser extensions that inject scripts into pages they serve.
  • Locking down iframe embedding (frame-ancestors) to prevent clickjacking attacks across your site and its subdomains.

CSP Pitfalls That Break Sites

  • Inline scripts without nonces - legacy templates often have <script>...</script> blocks that break under strict script-src 'self'. Add a nonce per response or refactor to external scripts.
  • Inline event handlers - onclick="doThing()" in HTML is blocked by default. Move to addEventListener in a separate file.
  • Third-party scripts that chain-load more scripts - Google Tag Manager, Hotjar, Intercom, and similar load additional scripts at runtime. Without strict-dynamic, you have to enumerate every secondary origin, which is brittle.
  • Google AdSense and Analytics - AdSense needs pagead2.googlesyndication.com, googleads.g.doubleclick.net, and several image domains in script-src, frame-src, connect-src, and img-src. GA4 needs *.google-analytics.com in script-src and connect-src. Google publishes the list in its Ad Manager and Analytics documentation.
  • Service workers - controlled by worker-src in CSP Level 3, previously by script-src. Mismatches between the two levels cause quiet failures.
  • Report-only policies never enforced - teams deploy Content-Security-Policy-Report-Only to gather data, then forget to migrate to enforced Content-Security-Policy. Reports without enforcement provide telemetry but zero actual protection.
  • Meta tag CSP vs header CSP - <meta http-equiv="Content-Security-Policy"> works for some directives but not for frame-ancestors, report-uri, or sandbox. Server headers are always preferred.

CSP Level 3 and Modern Best Practices

The W3C CSP Level 3 draft introduces several features beyond Level 2. strict-dynamic tells the browser that any script loaded by a script you trusted is also trusted, without enumerating every CDN. unsafe-hashes allows specific inline event handlers based on SHA hash. report-to replaces report-uri with a more flexible reporting API. Google\'s CSP Evaluator at csp-evaluator.withgoogle.com scores policies against known bypass patterns. Research from Google showed whitelist-based CSPs had a bypass rate of roughly 94% in 2016 due to JSONP endpoints on trusted domains; strict-dynamic with nonces is the recommended modern alternative.

Alternatives and Complementary Defenses

CSP is not a complete XSS defense. Combine it with output encoding, X-Content-Type-Options: nosniff, Referrer-Policy, and Permissions-Policy for layered defense. frame-ancestors in CSP replaces the legacy X-Frame-Options. Trusted Types (Level 3) offers stronger inline-script safety than nonces. Cloudflare, Netlify, and Vercel all support CSP via platform config; for Nginx, add_header Content-Security-Policy. Whatever platform you use, deploy as Report-Only first, collect reports for a week, then flip to enforcement once the violation stream is clean.

Frequently Asked Questions

What is the difference between CSP Level 2 and Level 3?

Level 2 is a W3C Recommendation (stable, fully supported). Level 3 is a Working Draft introducing <code>strict-dynamic</code>, <code>report-to</code>, Trusted Types, <code>unsafe-hashes</code>, and <code>worker-src</code>. Modern browsers (Chrome 52+, Firefox 49+, Safari 15.4+) implement most Level 3 features; older browsers gracefully ignore unknown directives. You can safely use Level 3 features today with Level 2 fallbacks for legacy clients.

Should I use <code>unsafe-inline</code>?

Only as a migration step, not long-term. <code>unsafe-inline</code> allows any inline script or style to execute, which defeats CSP's XSS protection. The modern approach is nonces (random tokens per response) or hashes (SHA-256 of specific script content) for the few inline scripts you cannot refactor. Google's CSP Evaluator flags <code>unsafe-inline</code> in production as a critical weakness.

How does CSP interact with Google AdSense?

AdSense requires several Google domains across directives: <code>script-src</code> needs <code>pagead2.googlesyndication.com</code>, <code>adservice.google.com</code>; <code>frame-src</code> needs <code>googleads.g.doubleclick.net</code>; <code>img-src</code> and <code>connect-src</code> need <code>*.googlesyndication.com</code>. Alternatively, use <code>strict-dynamic</code> with a nonce on the AdSense loader, which lets its chain-loaded resources execute without enumerating every origin.

What is <code>strict-dynamic</code> and why use it?

It extends trust from scripts loaded with a valid nonce or hash to any scripts those scripts subsequently load. Without it, loading Google Tag Manager forces you to enumerate every vendor tag it triggers (ads, analytics, chat widgets). With it, you trust the GTM loader via nonce and its child scripts execute without further policy edits. It is the Google-recommended approach for modern strict CSPs and drastically simplifies third-party script integration.

What is a nonce and how do I use it?

A nonce (number used once) is a cryptographically random token generated fresh per HTTP response, included both in the CSP header (<code>script-src &quot;nonce-abc123&quot;</code>) and as a <code>nonce="abc123"</code> attribute on each trusted script or style tag. The browser only executes scripts whose nonce matches. The randomness requirement means an attacker who injects a script tag cannot guess the nonce, so their script fails to execute. Use <code>crypto.randomBytes(16).toString("base64")</code> in Node or <code>secrets.token_urlsafe(16)</code> in Python to generate nonces server-side.

Why does <code>frame-ancestors</code> replace <code>X-Frame-Options</code>?

Both control iframe embedding by other origins (clickjacking defense). <code>X-Frame-Options</code> has three values and its <code>ALLOW-FROM</code> never worked in Chrome. <code>frame-ancestors</code> in CSP Level 2+ supports multiple origins and is better-specified. Use <code>frame-ancestors</code> for new deployments.

What does Report-Only mode actually do?

<code>Content-Security-Policy-Report-Only</code> tells the browser to detect violations and send reports to your <code>report-to</code> endpoint without blocking the violating resource. This lets you deploy a strict policy to production, watch what breaks in real traffic (via the collected reports), and tune the policy before flipping to enforced mode. The tradeoff: Report-Only provides zero actual protection - it is purely diagnostic.

How do I collect CSP violation reports?

Set up a <code>report-to</code> endpoint (Level 3) or <code>report-uri</code> (Level 2 fallback) that accepts POST requests with the violation JSON. Services like Report URI, Sentry, and Cloudflare Browser Insights accept CSP reports directly. Expect high volume initially; filter noise from browser-extension injections before acting.

Can I set CSP via a meta tag?

Partially. <code>&lt;meta http-equiv="Content-Security-Policy" content="..."&gt;</code> works for most directives but does NOT work for <code>frame-ancestors</code>, <code>report-uri</code>, <code>report-to</code>, and <code>sandbox</code>. The meta tag is applied after the browser has already started parsing the page, so some resources may already be requested. HTTP headers are always preferred; meta tag is a fallback for static hosts that cannot set headers.

Will CSP slow down my site?

No measurable performance impact for reasonable policies. The browser enforces CSP at resource-request time as part of normal checks; no extra round trip or significant computation. Very large policies (20KB+ of source lists) add marginal overhead but remain negligible. The real cost is authoring time and handling violation reports.

What happens if CSP blocks a critical resource?

The page still loads, but the blocked resource does not execute, so any dependent feature breaks silently from the user's perspective. The browser console shows a violation, and a report is sent to your endpoint if configured. Practical pattern: Report-Only first, audit for 1-2 weeks, patch legitimate sources, then enforce.

Does the generator transmit my policy?

No. The policy string is built entirely in your browser via a pure JavaScript function. No request goes to any server. This matters because CSP often names internal origins (staging hostnames, private CDN paths) that leak information about your infrastructure.

More Security & Privacy