What a Content-Security-Policy header actually does
How directives and fallbacks resolve, why a policy does not fix injection by itself, and how to roll one out safely.
A Content-Security-Policy header tells the browser which sources may load scripts, styles, images, frames, and other resources on your pages. It is one of the few defenses that reduces the impact of an injection bug, but it is also commonly deployed in a way that either breaks the site or provides no protection at all.
Directives and fallback
A policy is a list of directives, each with source values. The important detail is default-src: any resource type without its own directive falls back to it. A policy ofdefault-src 'self' therefore blocks external scripts, styles, frames, and connections unless you carve out exceptions. New directives must be added explicitly.
CSP policy builder shows the resolved fallback while you edit source lists, so you can see what a missing directive will actually allow.
What CSP does not do
CSP does not fix injection. If your application concatenates user input into HTML, that bug remains; the policy only limits what the injected code can reach. Treat it as defense in depth, and keep escaping, validation, and safe templating as the primary controls.
Rolling out a policy safely
- Start with
Content-Security-Policy-Report-Onlyso violations are reported without blocking anything. - Read the reports and either fix the source of each violation or add a deliberate exception.
- When reports are clean, switch to the enforcing header and keep monitoring.
Third-party scripts are the usual reason a policy grows complex. Each integration adds script, frame, and connect origins that must be listed individually. Inline scripts require hashes or nonces; adding 'unsafe-inline' to script-src trades nearly all of the protection away.
Related headers and checks
frame-ancestors controls who may embed your pages and replaces the older X-Frame-Options header for modern browsers. form-action limits where forms may submit, andbase-uri prevents injected base tags from changing how relative URLs resolve. littlekit's own headers include these directives, which is part of why the site can run tools without loading third-party code.
Teams that want an independent starting point can also test with the same builder used here, then diff the result against what the application actually needs.
