Skip to content
AZ Tools

Content-Security-Policy Builder

Build a CSP header from per-directive source lists, with three starter presets and live warnings for the dangerous wildcards.

Presets
Directives
Header
Content-Security-Policy: default-src 'self'; script-src 'self'; style-src 'self'; img-src 'self' data:; font-src 'self'; connect-src 'self'; object-src 'none'; base-uri 'self'; frame-ancestors 'none'
<meta> tag
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self'; style-src 'self'; img-src 'self' data:; font-src 'self'; connect-src 'self'; object-src 'none'; base-uri 'self'; frame-ancestors 'none'">

An empty directive falls through to default-src. Set default-src 'self' first, then narrow individual sources.

How to use

  1. Start from a preset (Strict locks everything to 'self', Relaxed allows inline + wildcards, API-only blocks navigation).
  2. Edit each directive — leave a field blank to drop it.
  3. Turn on report-only when shipping a new policy: violations are reported but not blocked.

About this tool

Show

Composes a Content-Security-Policy header from a directive-by-directive form. Each directive accepts a space-separated source list (keywords like 'self', 'none', 'unsafe-inline', or scheme/host sources). The tool flags policies that contain unsafe-inline, unsafe-eval, or a wildcard, omits empty directives from the output, and emits both the response header form and the equivalent <meta> tag (in report-only mode only the header, because browsers ignore a report-only policy delivered by <meta>). Switch to report-only mode while you're rolling a new policy out to production.

The two output forms are not equivalent, despite looking it. A <meta> tag cannot carry frame-ancestors, report-uri or sandbox, and it takes effect only from where it appears in the document, so anything the parser has already reached is unprotected. The response header has none of those limits and is the form to prefer whenever you control the server.

default-src is a fallback and not a floor. Directives that are absent inherit from it, but any directive you do write replaces it outright for that resource type, so adding script-src https://cdn.example.com to a policy with a strict default-src 'self' drops 'self' for scripts unless you list it again. Several directives, frame-ancestors and base-uri among them, do not fall back to default-src at all and are simply unrestricted when omitted.

'unsafe-inline' deserves the warning it gets, because it disables the protection most policies exist for. It is also silently ignored in any policy that carries a nonce or a hash, which is the modern way to allow specific inline scripts, and that interaction is a common source of a policy that behaves differently from how it reads.

Report-only mode is the right way to deploy. The browser evaluates the policy, reports what would have broken and blocks nothing, which surfaces the third-party scripts and inline handlers you had forgotten. Do note that the two headers are independent: shipping a report-only policy does not weaken an enforcing one you already serve, and neither does it enforce anything on its own.

Frequently asked questions

Header or <meta> tag — which should I use?

The HTTP header is preferred. The <meta> form is convenient when you can't edit response headers (static hosts, etc.), but it can't define frame-ancestors or report-uri/report-to, so it's strictly less powerful.

Why is the wildcard a warning?

* in a source list matches any URL, defeating the policy entirely. Pin sources to specific origins or use 'self' instead — if you genuinely need third-party scripts, list them explicitly.

How do I roll out a policy without breaking the site?

Send it as Content-Security-Policy-Report-Only first. The browser evaluates the policy and reports what would have been blocked, while still loading everything, so you can collect violations from real traffic before enforcing. Move to the enforcing header once the reports are quiet — a policy written from a guess about your own page almost always blocks something you forgot.

Why is my inline script still blocked when I allowed the domain it came from?

Because a host source only covers files fetched from that host. Code written inside the page has no URL to match, so it needs 'unsafe-inline', a hash of its exact contents, or a nonce that the server puts on both the header and the tag. The same applies to inline styles, to a style attribute, and to event handler attributes such as onclick.

Related tools