Skip to content
Content Security Policy

Build an XSS-proof CSP, or validate the one you already ship

Two tools in one. The builder composes a Content-Security-Policy header by picking the main directives (default-src, script-src, frame-ancestors and others) with canonical values such as 'self', 'none', nonces and 'strict-dynamic'. The validator analyses a CSP you paste in and flags the weaknesses that defeat its protection: 'unsafe-inline', a * wildcard, data: in script-src, a missing default-src or frame-ancestors. Everything is client-side: no data ever leaves your browser.

CSP builder

Pick a value for each directive. The preset baseline is already a safe policy ('self' everywhere, frame-ancestors 'none'): start here and only loosen where you must.

CSP validator

Paste an existing Content-Security-Policy (the full header is fine too). The weaknesses report updates as you type, no button to press.

How to use the builder and validator

  1. 1

    Set the directives in the builder

    Each directive has a dropdown with canonical values. The initial setup is already a safe baseline: default-src 'self', scripts and styles from your origin only, frame-ancestors 'none' against clickjacking. Tighten with 'none' whatever you do not need, and loosen only where the application genuinely requires it.

  2. 2

    Add trusted hosts and options

    In the additional hosts field list your legitimate third-party domains (the script CDN, the API endpoint). Enable upgrade-insecure-requests if you still have http:// assets, and set a report-uri to collect violations. Report-only mode generates the test header that observes without blocking.

  3. 3

    Generate and copy the header

    The Generate button produces the full Content-Security-Policy header, ready to paste into your Apache, Nginx or application middleware config. Copy it in one click. If you picked a nonce value, replace {NONCE} with the random token your server generates on every request.

  4. 4

    Validate an existing policy

    Paste the CSP you are already serving (or the whole header copied from curl -I) into the validator. The report highlights, in real time, what weakens the protection, assigns a severity to each finding, and computes an indicative hardening score. Fix it in the builder and regenerate.

Why CSP is the zero-cost defense against XSS

What it actually does. A Content-Security-Policy is an HTTP response header that tells the browser which origins it may load and run resources from: scripts, styles, images, fonts, frames, network connections. It is a declarative allowlist. With script-src 'self' the browser only runs JavaScript served by your own domain and rejects everything else, including the payload an attacker manages to inject through a cross-site scripting flaw. CSP does not fix the underlying injection bug, but it neutralises the exploitation step: the injected script simply never runs. It is defense in depth at zero performance cost, enabled with a single line of configuration.

The 'unsafe-inline' trap. CSP's security model rests on one distinction: code coming from a trusted source runs, inline code (inside <script> or in onclick= attributes) does not, because the browser cannot tell legitimate inline from injected inline. Adding 'unsafe-inline' to script-src reopens the exact door CSP was meant to close: any injected payload becomes executable again and the XSS protection drops to nothing. The modern alternatives are three: a random per-request nonce tagged only on legitimate scripts, an SHA-256 hash of the expected inline content, or 'strict-dynamic', which propagates trust from nonce-tagged scripts to the ones they dynamically load, freeing you from maintaining a host allowlist.

Builder and validator, one workflow. The builder starts from a deliberately restrictive baseline because in CSP security is the default and openness is the exception you justify. Composing the policy by choosing values avoids the syntax mistakes (a stray semicolon, a misspelled directive) that quietly make a CSP ineffective. The validator closes the loop on what already exists: paste the policy you serve and immediately see whether a *, a data: in script-src or a missing default-src is leaving a hole. Neither tool touches the network.

Report-only before enforce. Applying a strict CSP to a live site without testing breaks legitimate resources. That is what Content-Security-Policy-Report-Only is for: the policy is evaluated and every violation is logged and sent to your report-uri, but nothing is blocked. You watch real traffic for days or weeks, refine the policy against the reports, and only when false positives reach zero do you switch to the enforcing header. Private by design: the builder and validator run entirely in the browser, the site you are protecting is never contacted by our servers, so you can work on staging environments and intranets that are not publicly reachable.

The main directives, explained

DirectiveWhat it controlsTypical recommended value
default-srcFallback for every fetch directive you do not declare explicitly. The backbone of any policy.'self'
script-srcWhere the browser may load and run JavaScript from. The decisive directive for XSS.'self' or 'self' 'nonce-...'
style-srcSources for stylesheets and inline styles.'self'
img-srcImage sources; data: for inline base64 images.'self' data:
connect-srcEndpoints reachable via fetch, XHR, WebSocket, EventSource, sendBeacon.'self'
font-srcWeb font sources.'self'
frame-srcSources your page may load as a frame or iframe.'self' or 'none'
frame-ancestorsWho may embed your page in a frame. The modern successor to X-Frame-Options.'none'
base-uriRestricts the base tag URL so an injection cannot hijack relative paths.'self'
form-actionAllowed destinations for a form's action attribute.'self'

Glossary

Technical terms used on this page, briefly explained.

CSP (Content-Security-Policy) #
HTTP response header declaring to the browser which sources are allowed for each resource type. The primary defense against XSS and data injection. Standardised by the W3C as CSP Level 3.
Directive #
A single rule of the policy, in the form directive-name sources (e.g. script-src 'self'). Directives are separated by semicolons within the header.
Source list #
The list of sources following a directive. It can hold quoted keywords ('self', 'none'), schemes (https:, data:), hosts (https://cdn.example.com) and wildcards.
Nonce #
Number used once. A random, unpredictable token the server generates on every request, placed in the directive as 'nonce-...' and as a nonce attribute on legitimate scripts only. It makes inline safe without a host allowlist.
Hash #
A cryptographic digest (SHA-256, SHA-384, SHA-512) of the exact contents of an inline script or style, declared as 'sha256-...'. The browser runs the inline only if its hash matches. The static alternative to a nonce.
strict-dynamic #
A keyword that propagates trust: scripts loaded by an already-trusted script (via nonce or hash) are authorised in turn, ignoring hosts and wildcards in the policy. It simplifies CSPs that load modules dynamically.
frame-ancestors #
The directive that decides which origins may embed the page in a <frame> or <iframe>. With 'none' it is the clickjacking defense, more expressive than X-Frame-Options.
report-uri / report-to #
Directives that tell the browser where to send JSON reports of CSP violations. report-uri is the legacy form still supported; report-to is the modern successor built on the Reporting API. Essential for testing in report-only.

Frequently asked questions about CSP

What does a Content-Security-Policy actually do?
It tells the browser which origins may load and run each type of resource (scripts, styles, images, frames, connections). Anything outside the allowlist is blocked. The main benefit is against XSS: even if an attacker manages to inject code into the page, a tight script-src means the browser will not execute it.
Does my data stay in the browser?
Yes, entirely. Both the builder and the validator run in JavaScript inside your browser. The policy you compose or paste is never sent to any server, and the site you are protecting is never contacted by our infrastructure. You can use the tool offline and on staging or intranet environments that are not reachable from outside.
What is the difference between report-only and enforce?
The Content-Security-Policy header enforces the policy: resources outside the allowlist really are blocked. The Content-Security-Policy-Report-Only header evaluates the same policy but blocks nothing: it only logs violations and sends them to the report-uri. Report-only is the correct way to test a CSP on a production site before turning it on, so you catch false positives without breaking the user experience.
What is a nonce and how do I use it?
A nonce is a random token, different on every page load, generated by your server. You put it in the directive as script-src 'nonce-r4nd0m' and as an attribute on the tags you want to authorise: <script nonce="r4nd0m">. The browser runs only the inline scripts carrying the current nonce. Since an attacker cannot predict the value, their injected script will not have it and stays blocked. It is the safe alternative to 'unsafe-inline'.
Is 'unsafe-inline' really that dangerous?
Yes, on script-src it defeats the protection. CSP works precisely because it separates trusted code from arbitrary inline; 'unsafe-inline' tells the browser to run any inline script, including the one injected by an XSS. In practice you are back to square one. If you have a lot of legacy onclick=, migrate gradually to nonces, hashes or addEventListener in external JavaScript instead of leaving the directive open.
How do I stop my site from being loaded inside an iframe (clickjacking)?
With frame-ancestors 'none' in the CSP: no page, of any origin, will be able to embed yours in a frame or iframe. If you want to allow only your own origin, use frame-ancestors 'self'. This directive is more expressive and reliable than the old X-Frame-Options header, which only covered the DENY and SAMEORIGIN cases; having it is the modern clickjacking defense.
Does default-src cover all the other directives?
Only the fetch directives you have not declared explicitly. default-src is the fallback for script-src, style-src, img-src, connect-src, font-src and similar when those are missing. But beware: some important directives do NOT fall back to default-src, notably frame-ancestors, base-uri and form-action. Always declare them separately, otherwise they stay unrestricted even with a tight default-src.
How do I apply the CSP: HTTP header or meta tag?
The HTTP header is the recommended route: add_header Content-Security-Policy "..."; in Nginx, Header set Content-Security-Policy "..." in Apache, or a middleware in your application framework. Alternatively you can use <meta http-equiv="Content-Security-Policy" content="..."> in the HTML, but the meta tag has limits: it does not support frame-ancestors or report-uri and must sit before any resource. For complete protection use the header.
What is 'strict-dynamic' and when is it worth it?
It is a keyword that propagates trust: if a script authorised with a nonce dynamically loads others, those inherit the authorisation without needing their hosts listed in the policy. It pays off on modern applications with bundlers and dynamic module loading, where maintaining a domain allowlist would be brittle. When 'strict-dynamic' is present, hosts and wildcards in the same directive are ignored by browsers that support it.
How do I test a CSP without breaking the site?
Start in report-only with an active report-uri and watch the real violations generated by user traffic for a few days. Each report names the violated directive and the blocked resource: use them to widen the policy only where genuinely needed, preferring nonces and specific hosts over wildcards. When the stream of legitimate violations dries up, replace the report-only header with the enforcing one. Regenerate the final version in the builder and revalidate it before deploying.

Want a tight CSP without breaking your production site?

This tool composes and validates the policy, but rolling a CSP out gradually on a live site (report-only testing, violation-report analysis, wiring nonces into the middleware, hardening Apache or Nginx) takes method. I work on unmanaged VPS from the main European providers and on on-prem corporate infrastructure.

Let's talk about your CSP hardening