Craft Your Own Content Security Policy (CSP): From Basics to Battle-Hardened Defense
A practical, beginner-to-advanced guide to Content Security Policy (CSP). Learn how CSP works, why it matters, how to deploy it safely, and how to harden modern web apps against XSS, data exfiltration, and clickjacking.
Disclaimer
This article is published for educational and defensive security purposes only.
All techniques discussed are intended to help developers, security engineers, and defenders secure their applications, not to exploit them. Always test only on systems you own or have explicit permission to assess.
Introduction
Content Security Policy (CSP) is one of those security controls that almost everyone has heard of, but far fewer people truly understand or deploy correctly. For some teams, CSP feels intimidating. For others, it feels optional. In reality, CSP is neither exotic nor optional anymore - it is one of the most effective client-side defenses available for modern web applications.
What makes CSP especially powerful is that it doesn’t try to “fix” vulnerabilities like XSS directly. Instead, it limits the blast radius when something inevitably goes wrong. In a world of complex frameworks, third-party scripts, marketing pixels, analytics, and user-generated content, CSP is often the last line of defense between a small coding mistake and a large-scale compromise.
This guide is written to take you from zero to confident. We’ll start with what CSP actually is, move through real-world threats it mitigates, explain every important directive in plain language, and then walk step-by-step through designing, testing, and enforcing a strong CSP in production environments.
What Is Content Security Policy (CSP)?
Content Security Policy is a browser-enforced security standard that allows a website to declare which resources it trusts. These rules are delivered to the browser via HTTP response headers (or, less ideally, <meta> tags).
At a high level, CSP answers questions like:
- Where can scripts be loaded from?
- Are inline scripts allowed?
- Can the page be embedded in an iframe?
- Where is data allowed to be sent?
- Can plugins or legacy embeds run?
The browser then enforces these rules. If something violates the policy - for example, an injected script trying to execute - the browser blocks it automatically.
This is critical: CSP enforcement happens on the client side, independently of your backend logic.
Why Your Website Needs a CSP Yesterday
The Ultimate XSS Safety Net
Cross-Site Scripting (XSS) remains one of the most common web vulnerabilities. Even mature applications occasionally ship escaping bugs, logic flaws, or unsafe rendering paths.
A well-crafted CSP can:
- Block injected scripts from executing
- Prevent inline event handlers from running
- Stop malicious scripts from loading external payloads
CSP doesn’t eliminate XSS bugs - but it often turns them into non-exploitable issues.
Preventing Data Skimming and Formjacking
Modern attacks frequently target checkout flows and sensitive forms. A single injected JavaScript snippet can silently exfiltrate credit card numbers, passwords, or tokens.
CSP helps by:
- Restricting
connect-srcdestinations - Blocking unexpected script execution
- Preventing unauthorized data exfiltration endpoints
Even if malicious code lands on the page, CSP can stop it from sending data out.
Clickjacking Defense
Clickjacking attacks rely on embedding your site in an attacker-controlled iframe. CSP’s frame-ancestors directive gives you precise control over where your pages can be embedded - or blocks embedding entirely.
This protection is stronger and more flexible than legacy headers like X-Frame-Options.
Reducing Third-Party Risk
Analytics tools, ad networks, tag managers, and browser extensions are all common attack vectors. CSP allows you to explicitly enumerate trusted domains and block everything else by default.
This drastically limits the damage from compromised third-party scripts.
The Building Blocks of CSP
A CSP is made up of directives. Each directive controls a specific type of resource.
Below are the most important directives you’ll encounter.
| Directive | What It Controls | Typical Starting Value |
|---|---|---|
| default-src | Fallback policy for other directives | 'self' or 'none' |
| script-src | Allowed sources for JavaScript | 'self' + trusted CDNs |
| style-src | Allowed sources for CSS | 'self' |
| img-src | Allowed image sources | 'self' data: |
| connect-src | Allowed endpoints for fetch/XHR/WebSockets | 'self' |
| frame-ancestors | Who can embed your site in an iframe | 'none' |
| object-src | Allowed plugin content (Flash, embed, applet) | 'none' |
| form-action | Where forms are allowed to submit | 'self' |

The Dangerous Duo: unsafe-inline and unsafe-eval

When teams struggle with CSP, these two values are usually the reason.
unsafe-inline
This allows:
- Inline
<script>blocks - Inline event handlers like
onclick
Using unsafe-inline essentially disables CSP’s protection against XSS. Any injected inline script will run.
unsafe-eval
This allows JavaScript features like:
eval()new Function()- Certain dynamic code execution patterns
Attackers love eval. CSP should not.
The Bottom Line
If your CSP includes both:
script-src 'unsafe-inline' 'unsafe-eval'
…then your CSP is providing very little real security value.
Secure Alternatives: Nonces and Hashes

Modern CSP provides safe ways to allow necessary inline scripts without opening the door to attackers.
Nonces (Preferred for Dynamic Apps)
A nonce is a cryptographically random value generated per request.
Example CSP header:
Inline script:
Only scripts with the correct nonce will execute.
Hashes (Good for Static Inline Scripts)
Instead of allowing all inline scripts, you allow only a specific one.
The browser hashes inline scripts and executes only matching ones.
A Safe, Step-by-Step CSP Deployment Strategy

Step 1: Start in Report-Only Mode
Never deploy CSP enforcement blindly.
Use:
The browser will report violations without blocking anything.
Step 2: Collect Violation Reports
Add a reporting endpoint:
These reports show exactly what your site is loading.
Step 3: Build Your Initial Policy
Analyze reports. Identify:
- Required script domains
- Styles, fonts, images
- APIs and external services
Start restrictive. Add only what’s necessary.
Step 4: Iterate and Refine
Expect multiple rounds of refinement. CSP tuning is normal.
Your goal is zero unexpected violations.
Step 5: Enforce the Policy
Once stable, switch to enforcement:
Now the browser actively blocks violations.
Step 6: Monitor Continuously
Websites evolve. CSP must evolve with them.
Treat CSP reports like security telemetry.
Sample CSP Configurations
Example 1: Minimal Self-Hosted Site
Example 2: Site Using Google Analytics and Fonts
Example 3: Strict CSP with Nonce (Recommended)
Common CSP Pitfalls to Avoid
- Allowing
*wildcards - Blindly copying CSPs from other sites
- Leaving Report-Only enabled forever
- Forgetting to protect
connect-src - Using CSP as a replacement for input validation
CSP is defense-in-depth, not a silver bullet.
CSP as Part of a Secure Development Culture
The strongest teams treat CSP as:
- A design constraint
- A security contract
- A monitoring signal
Over time, CSP encourages better frontend hygiene, fewer inline scripts, and cleaner architecture.
Conclusion
Content Security Policy is one of the rare security controls that delivers outsized value for the effort invested. It protects users, limits attacker options, and gives defenders visibility into risky behaviors that would otherwise remain invisible.
If you care about XSS, data theft, clickjacking, or third-party risk - CSP is not optional anymore.
Start small. Measure. Iterate. Enforce.
Your future self - and your users - will thank you.
References
- W3C Content Security Policy Level 3
- MDN Web Docs: Content Security Policy
- Google Web Fundamentals: CSP
- OWASP Cheat Sheet: Content Security Policy