Craft Your Own Content Security Policy (CSP): From Basics to Battle-Hardened Defense

Craft Your Own Content Security Policy (CSP): From Basics to Battle-Hardened Defense

December 21, 2025 6 min read

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-src destinations
  • 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'

Clean infographic illustrating CSP directives like script-src, img-src, and frame-ancestors connected to browser enforcement logic.


The Dangerous Duo: unsafe-inline and unsafe-eval

Warning-themed illustration showing the 'unsafe-inline' and 'unsafe-eval' keywords breaking through a security barrier.

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

Diagram visualizing browser enforcement comparing blocked inline scripts versus allowed nonce-based scripts.

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:

Content-Security-Policy: script-src 'self' 'nonce-abc123'
HTTP

Inline script:

<script nonce="abc123">
  initApp();
</script>
HTML

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.

Content-Security-Policy: script-src 'self' 'sha256-AbCdEf...'
HTTP

The browser hashes inline scripts and executes only matching ones.


A Safe, Step-by-Step CSP Deployment Strategy

Professional architecture diagram showing a phased security rollout from 'report-only' mode to 'enforced' CSP mode.

Step 1: Start in Report-Only Mode

Never deploy CSP enforcement blindly.

Use:

Content-Security-Policy-Report-Only: default-src 'self'
HTTP

The browser will report violations without blocking anything.


Step 2: Collect Violation Reports

Add a reporting endpoint:

Content-Security-Policy-Report-Only:
  default-src 'self';
  report-uri https://csp-report.example.com
HTTP

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:

Content-Security-Policy: ...
HTTP

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

Content-Security-Policy:
  default-src 'self';
  img-src 'self' data:;
  object-src 'none';
  frame-ancestors 'none';
  form-action 'self';
HTTP

Example 2: Site Using Google Analytics and Fonts

Content-Security-Policy:
  default-src 'self';
  script-src 'self' www.google-analytics.com;
  style-src 'self' fonts.googleapis.com;
  font-src fonts.gstatic.com;
  img-src 'self' www.google-analytics.com;
  connect-src 'self' www.google-analytics.com;
  frame-ancestors 'none';
HTTP

Content-Security-Policy:
  default-src 'none';
  script-src 'self' 'nonce-random123' 'strict-dynamic';
  style-src 'self';
  img-src 'self' data:;
  connect-src 'self';
  frame-ancestors 'none';
  object-src 'none';
HTTP

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

Join the Security Intel.

Get weekly VAPT techniques, ethical hacking tools, and zero-day analysis delivered to your inbox.

Weekly Updates No Spam
Herish Chaniyara

Herish Chaniyara

Web Application Penetration Tester (VAPT) & Security Researcher. A Gold Microsoft Student Ambassador and PortSwigger Hall of Fame (#59) member dedicated to securing the web.

Read Next

View all posts

For any queries or professional discussions: herish.chaniyara@gmail.com