How to Fix Common Content-Security-Policy Errors
Read the console message, find the directive, then choose the safest fix: move, nonce, hash, or allow a specific host.
A Content-Security-Policy that blocks something it should not is one of the most frustrating errors in web development, because the page looks broken and the only clue is a console message. The good news is that the messages are precise. Once you can read them, almost every case has a standard fix.
Reading the console message
Refused to execute inline script because it violates the following
Content Security Policy directive: "script-src 'self'".
Either the 'unsafe-inline' keyword, a hash ('sha256-...'), or a nonce
('nonce-...') is required to enable inline execution.Three things are named: what was blocked (an inline script), which directive blocked it (script-src), and the options for allowing it. The directive tells you where to change the policy, and the first words tell you what kind of resource was involved.
Blocked inline scripts
Preferred order of fixes:
- Move the code into an external .js file served from an allowed origin. This is the cleanest fix.
- Add a nonce: generate an unpredictable random value for each response, put it in the header as 'nonce-VALUE' and in the script tag as nonce="VALUE". A nonce that is reused between responses protects nothing.
- Add a hash: put 'sha256-...' of the script's exact contents in script-src. Any change to the script, even whitespace, changes the hash, so this suits static snippets.
Content-Security-Policy: script-src 'self' 'nonce-r4nd0mPerResponse'
<script nonce="r4nd0mPerResponse">/* allowed */</script>Inline event handlers
Attributes such as onclick are inline script too, and a nonce does not cover them. Replace them with addEventListener calls in an allowed script. A keyword exists to allow specific handlers by hash, but rewriting is simpler and safer.
Blocked inline styles
style-src works the same way. A style element can be allowed with a nonce or hash. Style attributes on elements are governed by style-src-attr, and are commonly the last holdout when tightening a policy; move them into classes in a stylesheet where you can.
Blocked eval
eval, new Function and string arguments to setTimeout are blocked unless script-src includes 'unsafe-eval'. Fix the code that uses them rather than allowing them. Some libraries, mostly older template engines and bundler dev modes, need it; use production builds, which usually do not.
Third-party resources
Each kind of resource has its own directive, and the error names it. Allow the specific origin in the right place:
| Resource | Directive |
|---|---|
| Scripts | script-src |
| Stylesheets | style-src |
| Images | img-src |
| Fonts | font-src |
| fetch, XHR, WebSocket | connect-src |
| Iframes | frame-src |
| Media | media-src |
# Example: Google Fonts needs both a stylesheet and a font origin
Content-Security-Policy: style-src 'self' https://fonts.googleapis.com; font-src https://fonts.gstatic.comA data: image, such as a small inline icon, needs data: in img-src. Remember that * does not match data: or blob:, which must be named.
default-src and fallbacks
If a policy has no directive for a resource type, browsers use default-src. That is why a policy with only default-src 'self' can block a font or an image you never mentioned. Setting default-src 'none' and then allowing each type explicitly is stricter and easier to reason about.
strict-dynamic
With 'strict-dynamic' in script-src, a script that is trusted through a nonce or hash may load further scripts without each one being listed, and host allowlists and 'unsafe-inline' are ignored by browsers that support it. It simplifies policies for sites that load many scripts but needs a nonce or hash to work.
Other causes
- Two policies: if a response has more than one CSP, the browser enforces all of them, so the strictest combination wins.
- Browser extensions injecting scripts and generating violations that are not your code.
- A policy set by a CDN, proxy or hosting panel in addition to your application.
- A policy in a meta tag that lacks directives you assumed it had.
Roll out safely with report-only
Content-Security-Policy-Report-Only: default-src 'self'; script-src 'self' 'nonce-...'; report-to csp-endpointReport-only mode reports violations without blocking them. Run it on real traffic, fix what is reported, and switch to Content-Security-Policy when the noise stops. Reporting needs an endpoint to receive reports; without one you can still read violations in the browser console.
Check your policy
Paste your policy into the CSP Analyzer on DevCraftKit to see it parsed directive by directive, with plain-English explanations and findings for risky choices such as unsafe-inline, wildcards and missing object-src or frame-ancestors. The HTTP Security Headers Analyzer shows how the CSP fits among your other headers. Both read the text you paste in your browser; they cannot test how the policy behaves on your live pages.
Work from the message
When something breaks, copy the first line of the console error. It gives you the directive to edit and the resource type; start there rather than loosening the whole policy.
Conclusion
Fixing CSP errors is mostly translation: identify the directive, identify the resource, then choose the narrowest allowance that works. Prefer moving code and using nonces or hashes over keywords that switch protections off, and use report-only mode so you can learn before you enforce.
Frequently asked questions
- Why is my inline script blocked by CSP?
- A script-src policy without 'unsafe-inline' blocks inline script. Move the code to an external file, or allow that specific script with a per-response nonce or a hash of its exact contents.
- Should I just add 'unsafe-inline'?
- It makes the error go away but removes most of the protection CSP gives against injected script. Treat it as a last resort, and prefer nonces, hashes or external files.
- How do I test a policy without breaking my site?
- Send it in the Content-Security-Policy-Report-Only header first. Browsers report violations without blocking anything, so you can fix them before switching to enforcement.
- Why does my CSP in a meta tag not work for everything?
- Policies delivered in a meta element cannot use some directives, including frame-ancestors, report-uri and sandbox. Use an HTTP header for the full set.
Try it yourself
The tool that pairs with this guide.
CSP Analyzer
Analyze Content Security Policy headers, detect configuration issues, explain directives and sources, and generate safer CSP recommendations.
HTTP Security Headers Analyzer
Analyze HTTP response headers for security configuration issues.
Did this help you tighten your security headers?
If these free developer tools save you time, consider buying me a byte. Your support helps keep DevCraftKit free and growing.
Related articles
HTTP Security Headers Explained: A Practical Developer Guide
A handful of response headers tell the browser how to defend the page they came with. Here's what each one actually does.
Published
Content-Security-Policy (CSP) Explained With Examples
CSP is an allow-list for where your page's resources can load from. Here's how the directives fit together.
Published
What Is HSTS? Strict-Transport-Security Explained
HSTS closes a narrow but real window for downgrade attacks. Here's exactly what it enforces and how to configure it.
Published