Contents

Security › Web Application Security

Content Security Policy

A header restricting which scripts and resources a page may load.

Also known as: CSP, Content-Security-Policy header, script-src, CSP header

A Content Security Policy (CSP) is an HTTP response header that tells the browser which sources of scripts, styles, images and other resources the page is allowed to load or run. It’s a second line of defense against cross-site scripting (XSS): even if an attacker injects markup into your page, the browser refuses to run scripts that the policy doesn’t allow.

Content-Security-Policy: default-src 'self'; script-src 'self' https://cdn.example.com; img-src 'self' data:; object-src 'none'; frame-ancestors 'none'

This says: by default, load things only from my own origin. Scripts may come from my origin and one CDN. Images from my origin or data URLs. No plugins. And nobody may embed this page in a frame.

Key directives

DirectiveControls
default-srcThe fallback for resource types you don’t list
script-srcWhere JavaScript can come from (and whether inline scripts run)
style-srcStylesheets
img-src, font-src, media-srcThose resource types
connect-srcWhere fetch, XHR and WebSocket may connect
frame-src / frame-ancestorsWhat you can embed, and who may embed you (a clickjacking defense)
object-srcPlugins (set to 'none')
base-uri, form-actionLimit <base> tags and where forms can submit

The important part: inline scripts

The classic XSS payload is an inline script (<script>…</script> or onerror="…"). A strict policy blocks inline scripts unless you explicitly allow them with a nonce or hash:

<!-- header: script-src 'nonce-r4nd0m123' 'strict-dynamic' -->
<script nonce="r4nd0m123">initApp()</script>      <!-- allowed: matches the per-response nonce -->
<script>stealData()</script>                      <!-- injected, no nonce: blocked -->

The nonce must be a fresh, unguessable value per response. Avoid 'unsafe-inline' and 'unsafe-eval', which switch off most of the protection.

Rolling it out safely

  1. Start with Content-Security-Policy-Report-Only, which reports violations without blocking anything, and set up a reporting endpoint.
  2. Fix legitimate violations (third-party scripts, inline handlers).
  3. Tighten, then enforce.

Realistic expectations

  • It’s defense in depth, not a replacement for escaping output and sanitizing input (output encoding).
  • Third-party scripts (analytics, ads, widgets) complicate it. Each allowed source is trusted code on your page.
  • Overly broad allow-lists (*, whole CDNs hosting arbitrary user content) can be bypassed.
  • It’s one of several security headers. For third-party files you can also use Subresource Integrity.