What is Content Security Policy (CSP)?

Content Security Policy (CSP) is an HTTP response header that tells browsers which resources a web page is allowed to load. It is one of the most effective defences against Cross-Site Scripting (XSS) — a class of attack where an attacker injects malicious scripts into a page that are then executed in a visitor's browser.

The Problem CSP Solves

XSS attacks work because browsers, by default, trust and execute any JavaScript that appears in an HTML page — regardless of whether it was intended to be there. If an attacker can inject a <script> tag into a comment, a search result or a form error message, the browser executes it with full access to the page's cookies, local storage and DOM.

CSP breaks this assumption. By telling the browser "only execute scripts from these specific sources," injected inline scripts are blocked even if they end up in the HTML.

How CSP Works

The server sends a CSP header with the response:

Content-Security-Policy: default-src 'self'; script-src 'self' https://trusted-cdn.com; img-src *

The browser reads this policy before rendering the page. Any resource that does not match the policy is blocked and an error is logged in the developer console (and optionally reported to a reporting endpoint).

Key CSP Directives

DirectiveWhat it controls
default-srcFallback for all resource types not explicitly listed. Start here.
script-srcJavaScript files and inline scripts. The most security-critical directive.
style-srcCSS files and inline styles.
img-srcImages. img-src * is common since images rarely execute code.
connect-srcFetch, XHR, WebSocket connections. Important for APIs.
font-srcWeb fonts.
frame-srcSources allowed in <iframe> elements.
form-actionURLs that forms may submit to. Prevents form hijacking.
report-uri / report-toWhere the browser should send violation reports.

Source Values

ValueMeaning
'self'The same origin (scheme + hostname + port) as the page.
'none'Block everything for this directive.
'unsafe-inline'Allow inline scripts/styles. Significantly weakens CSP.
'unsafe-eval'Allow eval() and similar. Also weakens CSP.
'nonce-xxx'Allow a specific inline script with a matching nonce attribute.
'sha256-xxx'Allow an inline script whose SHA-256 hash matches.
https://cdn.example.comAllow resources from a specific URL or origin.
*Allow any source (no restriction for this directive).

Nonces — the Right Way to Allow Inline Scripts

Avoiding 'unsafe-inline' while still using inline scripts is done with nonces. The server generates a random value for each response and includes it in both the header and the script tag:

Content-Security-Policy: script-src 'nonce-r4nd0mV4lu3'

<script nonce="r4nd0mV4lu3">...</script>

An attacker who injects a <script> tag cannot know the nonce for the current response, so their script is blocked.

Report-Only Mode

Deploying CSP on an existing site can break things if the policy is too strict. The Content-Security-Policy-Report-Only header lets you test a policy without enforcing it. The browser reports violations but does not block anything. Once you are satisfied the policy does not break your site, switch to the enforcing header.

Practical Starting Point

A minimal but useful CSP for a server-rendered site with no third-party scripts:

Content-Security-Policy: default-src 'self'; img-src 'self' data:; object-src 'none'; base-uri 'self'; form-action 'self'

Try it: Security Headers Scanner → check if your site has CSP