ZeroTool Workbench

CSP Header Generator

Build Content-Security-Policy headers with directives, hashes, and nonces. Strict-mode templates, report-only fallback, plus Express and Nginx snippets. 100% client-side.

100% Client-Side Your data never leaves your browser Free · No Sign-Up
Mode
Inline script & style hash calculator
Hash will appear here
  

How to use

  1. Pick a Preset. Strict matches the OWASP “strict CSP” recommendation; Empty lets you start from a blank policy.
  2. Toggle Mode. Use Report-Only first so violations are reported but never block real users.
  3. For each directive, click keyword chips (‘self’, ‘strict-dynamic’, ‘none’), scheme chips (https:, data:), or type a host/path and press Enter.
  4. Use the Hash calculator to allow a specific inline script or style by content hash, or click + nonce to inject a fresh nonce.
  5. Switch the output tab to copy the form you need: HTTP header, HTML <meta>, Express (helmet), or Nginx add_header.

Strict CSP starter

The Strict preset is built around three rules: ‘self’ ‘strict-dynamic’ on script-src, ‘none’ on object-src, and ‘self’ on base-uri. Combined with per-request nonces or per-script hashes, this layout resists most reflected and stored XSS payloads. Add ‘self’ to form-action and ‘none’ to frame-ancestors to lock down phishing-style abuse.

Common pitfalls

  • ’none’ is exclusive. If you list any other source alongside ‘none’, the browser drops the directive.
  • frame-ancestors is HTTP only. Browsers ignore it when CSP is delivered via <meta>. The same applies to report-uri, report-to, and sandbox.
  • Hashes and nonces void ‘unsafe-inline’. Modern browsers fall back to the safer of the two when both are present.
  • Always set default-src. Missing fetch directives fall back to default-src; without it the browser applies no fallback for new directives added later.
  • Custom hosts cannot contain semicolons. A semicolon would terminate the policy and corrupt every directive after it.

Hashes vs. nonces

Use hashes for static inline content that ships with the page — analytics snippets, critical CSS, server-rendered helpers. Hashes work for static HTML and edge-cached responses because they do not need any per-request value.

Use nonces for dynamic content rendered per request. The server emits a Content-Security-Policy header containing ‘nonce-XYZ’ and stamps the same value on every <script nonce=“XYZ”> it renders. Pair nonces with ‘strict-dynamic’ so descendant scripts inherit trust without you maintaining a host allow-list.

Deployment cheat sheet

  • Nginx: copy the Nginx tab into your server block and reload — the always flag forces the header on error responses too.
  • Apache: use Header always set Content-Security-Policy ”…” in .htaccess or httpd.conf.
  • Express / Node: paste the helmet snippet, and remember to disable useDefaults so your policy is not silently merged with helmet defaults.
  • Cloudflare Pages / Vercel / Netlify: paste the HTTP header form into your platform’s headers config (_headers, vercel.json, netlify.toml).

FAQ

What is a Content Security Policy?

A CSP is an HTTP response header that tells browsers which sources of scripts, styles, images, fonts, frames, and other content are trusted. Together with output encoding, it is the strongest browser-side defense against cross-site scripting, clickjacking, and data injection attacks.

Should I deploy Enforce or Report-Only first?

Always roll out with `Content-Security-Policy-Report-Only` plus a `report-uri` (or `report-to`) endpoint. Watch real traffic for one to two weeks, fix legitimate violations in your code, then switch to enforced `Content-Security-Policy`.

Do I need 'unsafe-inline' for inline scripts and styles?

Avoid it whenever you can. Modern CSP supports per-script hashes (`'sha256-...'`, `'sha384-...'`, `'sha512-...'`) and per-request nonces (`'nonce-...'`). Use the inline-content hash calculator on this page to add a hash for a specific snippet.

What does 'strict-dynamic' do?

'strict-dynamic' lets a trusted nonced or hashed script load further scripts at runtime without listing every CDN. It is the recommended pattern for modern apps because it overrides host-based allow-lists for descendant scripts and stops trivial bypasses.

Where do I deploy the generated header?

Send `Content-Security-Policy` from your origin server (Nginx `add_header`, Apache `Header set`, Cloudflare Transform Rules, Vercel `headers`, etc.). The HTML `<meta http-equiv>` form is a fallback for static hosts but the browser ignores `frame-ancestors`, `report-uri`, `report-to`, and `sandbox` when CSP is delivered via `<meta>`.