Content-Security-Policy (CSP) Explained With Examples
CSP is an allow-list for where your page's resources can load from. Here's how the directives fit together.
CSP is fundamentally an allow-list: you declare which sources are trusted for each resource type, and the browser blocks anything that doesn't match. This is a walkthrough of the directives that come up most in practice, with realistic examples.
The basic shape
Content-Security-Policy: default-src 'self'; script-src 'self' https://cdn.example.com; img-src 'self' data:Each directive is a resource type followed by a space-separated list of allowed sources, and directives are separated by semicolons.
Common directives
| Directive | Controls |
|---|---|
| default-src | Fallback for any resource type without its own directive |
| script-src | Where JavaScript can load from |
| style-src | Where CSS can load from |
| img-src | Where images can load from |
| font-src | Where fonts can load from |
| connect-src | Where fetch/XHR/WebSocket connections can go |
| object-src | Controls <object>/<embed>/<applet> - usually set to 'none' |
| frame-src | Which origins can be loaded in an iframe on this page |
| frame-ancestors | Which origins are allowed to frame this page (clickjacking protection) |
| base-uri | Restricts what a <base> tag can set as the document's base URL |
| form-action | Restricts where forms on this page can submit to |
Source values
| Value | Meaning |
|---|---|
| 'self' | The page's own origin |
| 'none' | Nothing is allowed |
| 'unsafe-inline' | Allows inline scripts/styles - weakens the policy significantly |
| 'unsafe-eval' | Allows eval() and similar string-to-code APIs |
| https://example.com | A specific trusted origin |
| * | Any origin - effectively disables the restriction for that directive |
A realistic, reasonably strict policy
Content-Security-Policy: default-src 'self'; script-src 'self'; style-src 'self'; img-src 'self' data:; object-src 'none'; base-uri 'self'; form-action 'self'; frame-ancestors 'self'This allows the page to load its own scripts, styles, and images (plus inline data: URIs for images, common for small icons), blocks plugin content entirely, prevents base-tag hijacking, restricts form submissions to the same origin, and only allows same-origin framing.
Common weaknesses
- 'unsafe-inline' in script-src - permits inline scripts and event handlers, which removes most of CSP's XSS mitigation value. The fix is migrating to nonces (script-src 'nonce-<random>') or hashes for any inline scripts that are genuinely needed.
- 'unsafe-eval' - allows eval() and similar APIs, a common vector for executing injected code.
- A wildcard (*) or bare scheme (https:) in script-src - allows scripts from literally any host.
- No object-src 'none' - leaves plugin content (a legacy code-execution vector) unrestricted by default.
- Missing frame-ancestors - leaves clickjacking protection entirely to X-Frame-Options, if it's set at all.
// Weak - defeats most of CSP's purpose
Content-Security-Policy: script-src 'self' 'unsafe-inline' 'unsafe-eval' *Report-only mode
Content-Security-Policy-Report-Only uses the exact same directive syntax but only monitors and reports violations without blocking anything - useful for testing a new or tightened policy against real traffic before switching to enforcement.
Content-Security-Policy-Report-Only: default-src 'self'Checking your policy
Paste your CSP header into the HTTP Security Headers Analyzer to check for missing directives, unsafe-inline/unsafe-eval usage, wildcard sources, and permissive frame-ancestors - along with the rest of your security header configuration in one pass. For a directive-by-directive review of the policy on its own, use the CSP Analyzer.
Common mistakes
- Adding 'unsafe-inline' as a quick fix for a broken inline script, instead of migrating to nonces or hashes.
- Forgetting that CSP applies per-page, not site-wide by default - each response needs the header unless it's set centrally at a proxy/CDN layer.
- Not testing a new policy in report-only mode first, and breaking functionality in production.
- Setting default-src to a wildcard "to be safe" and functionally disabling the policy.
Summary
CSP directives each govern one resource type's allow-list. The value comes from being specific - listing actual trusted origins rather than wildcards, avoiding 'unsafe-inline'/'unsafe-eval', and restricting object-src and frame-ancestors even if you don't tighten anything else.
Frequently asked questions
- What does Content-Security-Policy do?
- It lets a server declare an allow-list for where scripts, styles, images, and other resource types are permitted to load from - the browser blocks anything that violates the policy.
- What does 'unsafe-inline' do in a CSP?
- It permits inline <script> blocks and inline event handlers to execute, which removes most of CSP's protection against injected scripts - it's one of the most common CSP weaknesses.
- What's the difference between Content-Security-Policy and Content-Security-Policy-Report-Only?
- The enforcing header blocks violations; the report-only version only logs/reports them without blocking anything, which is useful for testing a policy before turning on enforcement.
Try it yourself
The tool that pairs with this guide.
HTTP Security Headers Analyzer
Analyze HTTP response headers for security configuration issues.
CSP Analyzer
Analyze Content Security Policy headers, detect configuration issues, explain directives and sources, and generate safer CSP recommendations.
Did this help you tighten your security headers?
If these free developer tools save you time, consider buying me a byte. Your support helps keep DevCraftKit free and growing.
Related articles
HTTP Security Headers Explained: A Practical Developer Guide
A handful of response headers tell the browser how to defend the page they came with. Here's what each one actually does.
Published
What Is HSTS? Strict-Transport-Security Explained
HSTS closes a narrow but real window for downgrade attacks. Here's exactly what it enforces and how to configure it.
Published
CORS Explained: Access-Control-Allow-Origin, Credentials and Common Mistakes
CORS is a browser-enforced exception to the same-origin policy. Here's how it works and the one combination that goes wrong constantly.
Published