VibeSecurity

Fix

Fix: Refused to load the script (Content Security Policy)

This console error means your site has a Content Security Policy (CSP) and a script tried to load from somewhere the policy does not list. The policy is working. You need to decide whether that script belongs.

By the VibeSecurity team3 min read

What this means

Chrome prints: Refused to load the script '<URL>' because it violates the following Content Security Policy directive: "script-src ...". A CSP is an allow-list the server sends to the browser. The browser blocks any script whose source is not on the list. The message names the blocked URL and the directive that blocked it, which is all you need to fix it. Related messages for inline code start with 'Refused to execute inline script'.

Why it happens

  • You added a third-party script (analytics, payments, chat, maps, captcha) after the policy was written.
  • The policy was generated by an AI tool or copied from a template and lists only 'self'.
  • The framework injects inline scripts, as Next.js does, and the policy has no nonce or hash for them.
  • The policy is set in two places, for example a meta tag and a hosting header. When several policies apply, a resource must pass all of them.
  • The third party loads further scripts from a second domain that is not listed.

How to fix it

  1. 1Copy the blocked URL and the directive from the console message.
  2. 2Decide whether you trust and need that script. If you do not recognise it, leave it blocked and find out what is loading it.
  3. 3Find where the policy is set: next.config.js headers, middleware, vercel.json, a Netlify _headers file, or a meta tag.
  4. 4Add the script's scheme and host to script-src. Be specific: https://js.stripe.com, not https: or *.
  5. 5For inline scripts, generate a nonce per request and add it to both the policy and the script tags. The Next.js CSP guide shows the middleware for this.
  6. 6Deploy, reload with the console open and repeat for any further blocked sources. Check connect-src, img-src and frame-src too, because the same widget often needs those.
Before and after: allow one named host
Content-Security-Policy: default-src 'self'; script-src 'self'

Content-Security-Policy: default-src 'self'; script-src 'self' https://js.stripe.com; frame-src https://js.stripe.com; connect-src 'self' https://api.stripe.com

How to confirm the fix

  • Reload your page with devtools open. The console should show no 'Refused to' messages and the feature that depends on the script should work.
  • Check the policy your server really sends, using the curl command below. Look for duplicates.
  • Test the policy still blocks what it should: in the console on your own site, run the snippet below. The browser should refuse the script.
Check the live header, then test a block in your own console
curl -s -D - -o /dev/null https://www.yourapp.com | grep -i content-security-policy

const s = document.createElement('script');
s.src = 'https://example.com/not-allowed.js';
document.head.appendChild(s);

Frequently asked questions

I never set a CSP. Where did it come from?

Check your framework config, middleware, hosting config files and the HTML head for a meta tag. Starter templates and AI tools often add one. Some embedded environments and browser extensions add their own.

Can I test a policy change without breaking the site?

Yes. Send the new policy in the Content-Security-Policy-Report-Only header first. The browser reports violations in the console without blocking anything.

Should I just remove the CSP?

No. It is a useful second layer against cross-site scripting. Adjusting it for one trusted host takes a few minutes.

Sources

  1. 1.MDN: Content Security Policy (CSP)
  2. 2.MDN: CSP script-src
  3. 3.Next.js: Content Security Policy
  4. 4.OWASP Content Security Policy Cheat Sheet
  5. 5.MDN: Content-Security-Policy-Report-Only