Loading Content Security Policy Analyser…
Paste the header text. Nothing is fetched and no request is made— the policy is split apart by JavaScript in your own browser, which is also why this cannot check a policy by visiting a site for you.
The header name may be left on or taken off. Several policies, on several lines or separated by commas, are read as several policies.
Paste a policy above and every directive in it is explained here.
It is worth being honest about this, because a tool that treats 'unsafe-inline' as a careless mistake is no use to the people who have it. The usual cause is a third-party script. This site carries Google advertising, and an ad tag is a script whose entire job is to inject further scripts from hosts it chooses at runtime and does not publish in advance. There is no allowlist that covers that, so a policy written around one drifts towards a wildcard or an inline exemption, and the policy stops mitigating anything.
The way out is the pair in the first example above: a nonce on the one script tag you control, plus 'strict-dynamic'. A script the browser already trusted may then load more, so trust follows the chain rather than a list of hostnames, and host and scheme sources stop being consulted at all. It is more work than pasting a hostname, and it is the difference between a policy that documents your vendors and one that survives an injection.
default-src is a fallback for the fetch directives and nothing else. Each of these is wide open when it is absent, however tight the rest of the policy is.
base-uriform-actionframe-ancestorssandboxreport-torequire-trusted-types-fortrusted-typesupgrade-insecure-requestsdefault-srcFallback for the fetch directives below, and only for those.script-srcWhere script may be loaded from, and whether inline script and eval are allowed.falls back to default-srcscript-src-elemNarrows script-src to <script> elements only.falls back to script-src, then default-srcscript-src-attrNarrows script-src to inline event handler attributes only.falls back to script-src, then default-srcstyle-srcWhere stylesheets may come from, and whether inline style is allowed.falls back to default-srcstyle-src-elemNarrows style-src to <style> and <link rel=stylesheet>.falls back to style-src, then default-srcstyle-src-attrNarrows style-src to inline style attributes.falls back to style-src, then default-srcimg-srcWhere images may be loaded from.falls back to default-srcfont-srcWhere web fonts may be loaded from.falls back to default-srcconnect-srcWhere fetch, XHR, WebSocket, EventSource and sendBeacon may talk to.falls back to default-srcmedia-srcWhere audio and video may be loaded from.falls back to default-srcobject-srcWhere <object> and <embed> content may come from.falls back to default-srcmanifest-srcWhere the web app manifest may be loaded from.falls back to default-srcchild-srcFallback for frame-src and worker-src.falls back to default-srcframe-srcWhat this page may load into a frame.falls back to child-src, then default-srcworker-srcWhere Worker, SharedWorker and ServiceWorker scripts may come from.falls back to child-src, then script-src, then default-srcbase-uriWhat a <base> element may set the document base URL to.sandboxApplies iframe sandbox restrictions to the document itself.form-actionWhere a form on this page is allowed to submit.frame-ancestorsWho may frame this page. Replaces X-Frame-Options.report-toNames a reporting group declared by the Reporting-Endpoints header.report-uriWhere violation reports are posted. Deprecated, still the widest supported.upgrade-insecure-requestsRewrites http:// subresource requests to https:// before they are made.require-trusted-types-forWith the value 'script', forces DOM sink assignments through a Trusted Types policy.trusted-typesNames the Trusted Types policies this document may create.block-all-mixed-contentRemoved from CSP Level 3. Browsers block or upgrade mixed content on their own.plugin-typesRemoved from CSP Level 3 along with browser plugin support.referrerRemoved. The Referrer-Policy header does this job.reflected-xssRemoved. It configured XSS filters that no browser still ships.prefetch-srcRemoved from CSP Level 3 before any browser kept it.navigate-toProposed and withdrawn. It never became part of CSP Level 3.require-sri-forNever reached CSP Level 3; it was dropped from the Subresource Integrity work.A Content-Security-Policy header is a semicolon-separated list of directives, and each directive answers one question: where may this kind of thing be loaded from? script-src answers it for script, img-src for images, connect-src for whatever the page fetches in the background. Before every load the browser consults the matching directive and refuses anything the list does not cover.
Two behaviours make the header harder to read than that suggests. A directive you leave out does not fail closed — if it is a fetch directive it falls back to default-src, and if it is not, nothing governs it whatsoever. And a directive written twice is never merged: the browser keeps the first occurrence and discards the rest, so a tightening appended to the end of a long policy quietly achieves nothing at all.
Almost every published policy allows inline script, and treating that as simple carelessness is the fastest way to make a tool like this one useless. The usual cause is a third-party tag. This site carries Google advertising, and an ad tag is a script whose entire purpose is to load further scripts from hosts it selects at runtime and does not publish in advance. No list of hostnames can cover that, so a policy written around one drifts towards a wildcard — and a wildcard script source mitigates precisely nothing.
There is a way out, and it is more work than pasting a hostname in. Put a freshly generated nonce on the one script tag you control, and add strict-dynamic beside it. Trust then follows the chain, because a script the browser has already accepted is permitted to load more, and host and scheme sources stop being consulted at all. That is the whole distance between a policy that lists your vendors and a policy that survives an injection.
default-src stands in for the fetch directives and for nothing else, which is the most common misreading of the entire header. base-uri, form-action, frame-ancestors and sandbox all sit outside it, and each one is unrestricted when absent however narrow the rest of the policy looks.
The consequences are specific. With no base-uri, a single injected base element re-points every relative URL on the page. With no form-action, an injected form posts whatever the visitor typed — a password their manager filled in seconds earlier — to any origin the attacker likes. With no frame-ancestors, who may frame the page is decided solely by X-Frame-Options, assuming that header is being sent.
Send it under the report-only header name first. The browser evaluates the policy in full, posts every violation to the endpoint named by report-uri or report-to, and then permits the load regardless. A fortnight of reports from real traffic finds the analytics snippet nobody remembered, the marketing tag added by someone in another department, and the page still pulling a font over plain http — none of which appear during local testing.
Then move the same text to the enforcing name and leave a slightly stricter version behind in report-only. Violation reports are what turn a policy into something you can tighten by degrees, rather than something written once and afterwards too frightening to touch.
No. It narrows what an injection can be turned into, and the bug is still sitting there. A policy that permits inline script mitigates almost nothing, which is why the first thing to check is whether a nonce or a hash sits beside that exemption.
Usually because it is identical on every response. A nonce baked into a static header, or into a page a CDN is caching, is public knowledge and an attacker just copies it. It has to be regenerated per response and carry at least 128 bits of entropy.
Not a conflict. Both are enforced independently and a load has to satisfy each of them, so the result is the intersection. A second policy can only ever tighten a page, which makes it a safe way to add one rule without editing an existing header.
For most directives yes, and it is the fallback when you cannot configure the server. Some directives are refused there — frame-ancestors, sandbox and report-uri among them — because by the time the markup is parsed the decisions they govern have already been taken.