Questions
Why is my CSP blocking my own scripts?
Because the policy does not list the source the script came from, and a Content Security Policy denies anything it does not explicitly allow. The browser console names the violated directive and the blocked URL on every refusal, which is almost always the whole diagnosis. The wrong reflex is adding `'unsafe-inline'` to make the error go away: that disables the protection the policy exists to provide.
Read the violation before changing anything
Every refusal logs a message naming the directive that blocked it, the source that was refused, and the policy that was in force.
`script-src` blocked an external file, an inline `<script>` block, or an inline event handler — and the three need different fixes.
`connect-src` blocked a fetch or XHR, `style-src` a stylesheet, `img-src` an image, `frame-src` an embed.
A directive you never wrote appearing in the message means `default-src` is being applied as the fallback, which is how a policy blocks things its author never thought about.
The four refusals that account for most of them
An inline script. The policy has no way to distinguish yours from an injected one, so it refuses both unless the block is identified by a nonce or a hash.
An inline event handler such as `onclick`, which is refused by `script-src` and cannot be rescued by a nonce — it needs `'unsafe-hashes'` or, better, moving to an event listener.
A third-party origin not listed. Analytics, tag managers, chat widgets and font providers each need their own entry, and several load further resources from origins you have to discover.
`eval`, used by some libraries and by most templating done at runtime. It requires `'unsafe-eval'`, which is worth avoiding by building templates ahead of time instead.
Why 'unsafe-inline' is the wrong answer
It permits every inline script on the page, including one injected through a cross-site scripting flaw. That is the exact attack the policy was deployed against.
It also silently disables any nonce or hash in the same directive for browsers that support them, so a policy carrying both is weaker than the nonce alone.
The supported alternatives are a nonce — a random value regenerated per response and repeated on each allowed block — or a hash of the block's exact contents.
`'strict-dynamic'` is the modern shape: trust scripts loaded by an already-trusted script, which removes the need to enumerate every third-party origin.
Deploy it in report-only mode first
`Content-Security-Policy-Report-Only` applies the policy without blocking anything and reports what it would have refused.
Leave it running long enough to cover the pages and journeys real visitors use, not just the home page. Consent flows and logged-in areas load different scripts.
Collect the reports through the `report-to` directive rather than reading consoles by hand, which only ever samples your own browsing.
Switch to the enforcing header once the report stream is quiet. A policy moved to enforcement while reports are still arriving will break something.
How to check what is actually in force
`curl -sI https://example.com | grep -i content-security-policy` shows the policy the server sends, which is not always the one in the configuration file.
Two policies can be present at once — one from the application and one from a CDN — and a browser enforces the intersection, which is stricter than either alone.
VeriFixScan reports `security.csp` with the policy observed on the crawled pages, which is the served value rather than the intended one.
A policy that differs between routes is a routing problem rather than a policy problem, and it shows up only by checking more than the home page.
Frequently asked questions
- Should I add 'unsafe-inline' to fix CSP errors?
- No. It permits every inline script including an injected one, and it disables nonces and hashes in the same directive. Use a nonce or a hash instead.
- Why is a directive I never wrote blocking things?
- default-src is the fallback for directives you did not specify. Anything not covered explicitly inherits it.
- How do I deploy a CSP safely?
- Start with Content-Security-Policy-Report-Only, collect violation reports across real journeys, and switch to enforcement once the stream is quiet.
Sources
Related
VeriFixScan crawls a site and applies its checks to every page it reaches, keeping the evidence behind each finding. Scanning one website is free.
Scan a website