Content Security Policy (CSP)
A header telling the browser which scripts, styles and connections a page may load, so injected code is refused before it runs.
See it
What it is
A response header that tells the browser what this page is allowed to load and run, directive by directive: script-src for JavaScript, style-src for CSS, img-src, connect-src for fetch and websocket destinations, frame-ancestors for who may iframe you, form-action for where forms may post. Anything outside the policy is refused by the browser and logged to the console. It is a second line of defense: it does not stop an attacker injecting a script tag, it stops that script from executing.
The modern shape is a strict, nonce-based policy rather than a list of trusted hosts. Generate a random nonce per response, put it on your own script tags, and write script-src 'nonce-abc123' 'strict-dynamic' so scripts your trusted code loads inherit trust while injected ones do not. Add object-src 'none' and base-uri 'none', which close two classic bypasses. Roll it out with Content-Security-Policy-Report-Only plus a reporting endpoint first, watch what breaks for a week, then enforce.
Gotcha: 'unsafe-inline' in script-src cancels the whole point, and it is exactly what a tag manager or an inline onclick will push you to add. If you need one inline block, use its nonce or hash instead. Second gotcha: host allowlists look safe and often are not, because one allowed CDN hosting an old JSONP endpoint or an unlocked Angular build gives an attacker a way in through your own policy. Also note frame-ancestors is the replacement for X-Frame-Options, and CSP is useless against server-side holes: it is a browser-side control only.
Ask AI for it
Add a strict nonce-based Content Security Policy to this app. Generate a cryptographically random nonce per request in middleware, expose it to the render layer, and attach it to every first-party script and style tag. Send: default-src 'self'; script-src 'nonce-{NONCE}' 'strict-dynamic' https: ; object-src 'none'; base-uri 'none'; frame-ancestors 'none'; form-action 'self'; img-src 'self' data:; connect-src 'self' plus the exact API and analytics origins this app calls. Remove every inline event handler and inline script that cannot carry the nonce, and never add 'unsafe-inline' or 'unsafe-eval' to script-src. Ship it first as Content-Security-Policy-Report-Only with a report-to endpoint that logs violations, and note which third-party scripts will need a nonce or a hash before enforcement.