Content-Security-Policy playbook: stop XSS without blocking your app
Build a practical CSP in phases, avoid unsafe-inline pitfalls, and keep third-party scripts under control.
12 min read • Frontend teams, security engineers
Why CSP matters
CSP is your strongest browser-level control against script injection and many classes of XSS. It defines where scripts, styles, frames, images, and connections are allowed to load from.
A weak CSP can create false confidence, so quality matters more than simply having the header.
Baseline policy for modern apps
Start with a strict baseline and open only what your app truly needs. Prefer nonce-based script loading and avoid wildcard source lists.
Implementation checklist
- Set default-src 'self'.
- Use script-src with nonces or hashes for inline scripts.
- Set object-src 'none' and base-uri 'self'.
- Set frame-ancestors explicitly to control embedding.
- Monitor violations with report-to / report-uri.
Example header
Content-Security-Policy: default-src 'self'; script-src 'self' 'nonce-<generated-per-request>'; object-src 'none'; base-uri 'self'; frame-ancestors 'none'
What to avoid
Avoid unsafe-inline and unsafe-eval in production unless there is a temporary migration plan and a hard deadline to remove them.
Avoid broad wildcards like script-src * because they eliminate most CSP protection.