Why does a missing or wildcard script-src directive undermine CSP?

csp-script-src-weak global

The issue

A policy that lets scripts load from any origin doesn’t protect against cross-site scripting or a compromised third-party script, which is most of what a Content Security Policy is for. The header is present and scanners that only check for it pass, so the gap tends to stay.

The cause is a script source list that allows everything: *, or a bare scheme such as https:, in script-src, or in default-src when script-src isn’t set.

Scope

script-src applies to every script in the document that receives the policy, external and inline. It is normally set once, in the shared policy.

How to check you have it

  • In probeo: a policy that lets scripts come from *, https: or http: is reported as csp:script-src-wildcard, graded major. A 'strict-dynamic' source switches this off, because it makes the browser ignore those entries.
  • By hand: run curl -sI https://your-site.example/ | grep -i content-security-policy, find script-src, or default-src if script-src is absent, and read its sources.
  • With a tool: Google’s CSP Evaluator flags broad script sources.

The fix

Set script-src to 'self' plus each origin the site really loads scripts from.

List third-party origins one by one. If the list grows long, a nonce-based policy with 'strict-dynamic' is the alternative: the server adds a fresh nonce to each script tag it trusts, and scripts those load are trusted in turn. Setting script-src explicitly also means a change to default-src can’t loosen it by accident.

Done when: the policy names specific script sources, or uses nonces with 'strict-dynamic', and the check above comes back clean.

Do not

  • Do not use *, https: or http: as a script source.
  • Do not add data: or blob: to script-src.
  • Do not assume a present policy restricts scripts until you have read script-src.

How the fallback works

For a script, the browser uses script-src if it is set, and default-src if not. A policy such as default-src 'self'; style-src 'self' restricts scripts to the site’s own origin through default-src. A policy with neither directive places no limit on scripts at all.

FAQ

If default-src is set to ‘self’, does that cover scripts?

Yes, while script-src is absent. Setting script-src explicitly makes the intent visible and lets scripts carry their own rules, such as nonces, without changing other resource types.

Why is a wildcard script-src worse than no CSP at all?

In what the browser allows, they are the same. The difference is that a wildcard policy looks configured, so people stop checking.

Can script-src and default-src coexist?

Yes. script-src governs scripts, and default-src covers the fetch directives that aren’t set. default-src 'none'; script-src 'self' is a common pattern.

What if I need scripts from many third-party origins?

List each one, or move to nonces with 'strict-dynamic'. Each origin listed is a decision to trust it, and a long list is a sign of how many decisions have been made.

Does this affect inline scripts?

Yes. Inline scripts run only if script-src allows 'unsafe-inline', or carry a matching nonce or hash. A policy whose script-src or default-src has none of these blocks them.

How do I audit what scripts currently load on my pages?

Send a strict policy as Content-Security-Policy-Report-Only with a reporting endpoint. Every script it would block is reported, which gives the real list of sources to build the enforced policy from.

Which product detects this

Probeo checks this on every page of your site as part of Site Clarity. This page explains one instance; the product tells you every page that has it.