CSP Generator
Build a Content-Security-Policy from a form, with warnings for settings that defeat it. Outputs the header, a Report-Only version, a meta tag and NGINX config.
Assemble a Content-Security-Policy by picking directives and sources rather than writing the header by hand. Settings that quietly defeat the policy, such as unsafe-inline on script-src, are flagged as you go, and the same policy is available as a header, a Report-Only header, a meta tag or an NGINX directive.
Content-Security-Policy: default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' data:; connect-src 'self'; object-src 'none'; frame-ancestors 'self'; upgrade-insecure-requests
// CSP Generator: Features
What a CSP actually buys you
A Content-Security-Policy tells the browser where a page is allowed to load things from. Anything from an origin you have not permitted is blocked by the browser itself, which means that even when an XSS hole exists, the injected script may never run. If escaping output is the defence that stops injection, CSP is the second layer that stops the injected code from executing. To inspect the headers a site is already sending, the HTTP Header Analyzer explains each one.
How default-src relates to the other directives
default-src supplies the fallback for every resource type you have not named explicitly. Set script-src and scripts use it; leave it out and they fall back to default-src. That is why default-src self is the right first line: directives you forget are restricted automatically rather than left open. Without it, any type you did not think of is unrestricted, which is the most common way a policy ends up weaker than its author believed. The generator warns when default-src is off.
What unsafe-inline takes away
Adding unsafe-inline to script-src permits inline script elements and event handler attributes to run. That is precisely the shape most XSS payloads take, so the policy stops providing meaningful XSS protection. It is tempting because it makes existing inline scripts work immediately, but the correct fix is a nonce or a hash. Note also that browsers implementing CSP Level 2 and later ignore unsafe-inline entirely when a nonce or hash is present, so combining them only helps very old clients.
Try it in Report-Only first
Enforcing a new policy straight away tends to break something: an analytics script, an embedded widget, a font you forgot about. Serving the same policy as Content-Security-Policy-Report-Only blocks nothing and reports violations instead. Run it that way for a few days, read what it catches, adjust, and only then enforce. The generator emits the Report-Only form of whatever you have configured, which makes this the default path rather than an extra step.
Presets for the configurations people actually run
Google Analytics, Google AdSense and Google Fonts each need several specific hosts, and missing one produces a policy that works until it does not. Presets for all three are included, along with a strict baseline and a more permissive standard setup. Loading a preset and then adding your own hosts is faster and less error-prone than starting from an empty policy. For cross-origin request configuration rather than content restrictions, see the CORS Header Generator.
// CSP Generator: FAQ
What does a CSP protect against?
- Primarily cross-site scripting. Even if an attacker injects a script, the browser refuses to run it unless its origin is permitted. Beyond that, frame-ancestors prevents clickjacking, form-action stops a form being retargeted, and upgrade-insecure-requests eliminates mixed content. CSP is a second layer, not a replacement for escaping output correctly.
Where should I start?
- With default-src self. That single directive establishes the shape of the policy and covers every resource type you have not named. Then add the external hosts your site genuinely uses to script-src, img-src and connect-src. The standard preset is exactly this arrangement.
Is unsafe-inline always wrong?
- On script-src, effectively yes: it permits the thing CSP exists to prevent. On style-src the risk is lower and it is widely tolerated in practice, though style-based data exfiltration techniques do exist. Where inline code is unavoidable, use a nonce or a hash rather than opening the directive.
How do nonces work?
- Generate a random value per request, put it in the header as nonce-value, and set the same value as the nonce attribute on your script tags. Only matching scripts run. The value must change on every request; a fixed nonce is no better than unsafe-inline because an attacker can simply reuse it. The generator emits a placeholder for you to substitute server-side.
Can I set the policy in a meta tag?
- You can, with limitations. frame-ancestors, report-uri and sandbox are ignored in a meta tag, so those require an HTTP header. A meta policy also only applies from the point the parser reaches it, leaving anything loaded earlier uncovered. Prefer the header wherever you control the server.
My site broke after I enabled it. What now?
- The browser console names the directive and the URL that was blocked, which is usually enough to identify the missing host. While you are working it out, serve the policy as Report-Only so violations are reported without anything being blocked. Switch the output format here to Report-Only to get that version.
Why set object-src to none?
- Plugin content loaded through object and embed elements has historically been an attack vector, and essentially no modern site needs it. Setting object-src none removes that surface at no cost, which makes it one of the few directives with no trade-off worth discussing.
What is the difference between frame-ancestors and X-Frame-Options?
- Both stop your page being framed by another site, which is the clickjacking defence. frame-ancestors is the CSP directive that supersedes X-Frame-Options, allows multiple origins and wildcards, and takes precedence when both are present. Use frame-ancestors for anything new.
Is report-uri still usable?
- Yes, although the specification is moving towards report-to together with the Reporting-Endpoints header. Browser support for the newer mechanism is uneven, so sending both, or starting with report-uri, remains the pragmatic choice. You will need an endpoint of your own or a third-party collector to receive the reports.
Is the policy I build sent to a server?
- No. Everything is assembled in your browser. That matters here because a policy lists your internal hostnames, unreleased subdomains and the third-party services you depend on, which together describe your infrastructure fairly precisely.
// How to Use CSP Generator
-
Start from a preset
Pick the strict or standard baseline, or one of the presets for Google Analytics, AdSense and Google Fonts. Starting from a preset is faster than an empty policy and avoids missing one of the several hosts those services need.
-
Choose directives and sources
Enable the directives you need, select keyword sources such as self, and add your own hosts in the text field, separated by spaces. Selecting none clears the other sources for that directive, since it cannot be combined with anything else.
-
Read the warnings, then copy
Warnings appear for unsafe-inline, a missing default-src and similar settings that weaken the policy. Once you are satisfied, choose an output format and copy. For a first deployment, take the Report-Only version and enforce only after reviewing the violations it reports.
Category Security