Back to Guides
Guide5 October 2026

How to Implement a Content Security Policy (CSP) Header

Decloak is an AI-powered web security intelligence platform that scans a site's HTTP/TLS posture, JavaScript, and third-party scripts to produce a report anyone can read. This guide is part of Decloak's library of practical, source-backed security guidance.

In this guide
  1. Key takeaways
  2. What is a CSP header and why should I use it?
  3. How do I deliver the CSP header?
  4. What is the basic syntax of a CSP policy?
  5. Which fetch directives should I include?
  6. How do I block everything by default?
  7. How can I safely allow inline scripts or styles?
  8. How do I prevent dangerous eval - style APIs?
  9. How can I stop my site from being framed (clickjacking protection)?
  10. How do I upgrade mixed content automatically?
  11. How do I get feedback on policy violations?
  12. What are best - practice implementation steps?
  13. How does CSP complement other security layers?
  14. Quick example for a typical Node.js Express app
  15. Summary

Key takeaways

What is a CSP header and why should I use it?

A Content - Security - Policy (CSP) header tells browsers which resources are allowed to load, dramatically reducing the risk of cross - site scripting (XSS) and data - injection attacks. By enforcing a whitelist, any unexpected script, style, or frame is blocked before it can execute.

How do I deliver the CSP header?

Set the header in every HTTP response, not just the main HTML page. Use the standard header name Content - Security - Policy for enforcement or Content - Security - Policy - Report - Only while testing. Example (NGINX):

add_header Content - Security - Policy "default-src 'self'; script-src 'self' 'nonce-${nonce}';" always;

Replace ${nonce} with a per - request generated value.

What is the basic syntax of a CSP policy?

A CSP is a semicolon - separated list of directives. Each directive consists of a name followed by one or more source expressions. Example:

Content - Security - Policy: default-src 'self'; img-src https: cdn.example.com;

default-src provides a fallback for any resource type that lacks an explicit directive.

Which fetch directives should I include?

Start with a minimal set and expand as needed:

DirectivePurpose
default-srcFallback for all types
script-srcAllowed JavaScript sources
style-srcAllowed CSS sources
img-srcAllowed image origins
font-srcAllowed web - font origins
connect-srcAllowed XHR, WebSocket, EventSource
media-srcAllowed audio/video sources
object-srcAllowed plugin objects
frame-ancestorsOrigins allowed to embed the page

How do I block everything by default?

Use 'none' for a directive you want to completely disallow, for example:

object-src 'none';

If you omit a directive, the default-src value applies.

How can I safely allow inline scripts or styles?

Nonces - Generate a random base64 string for each response, add it to the header and to each <script>/<style> tag:

<script nonce="abc123def456">…</script>

Header:

script-src 'nonce-abc123def456';

Only elements with the matching nonce will execute.

Hashes - Compute a SHA - 256/384/512 hash of the inline code and list it in the directive:

script-src 'sha256 - XyZ…';

Hashes are ideal for static pages because the content does not change.

Never use 'unsafe-inline'; it defeats the purpose of CSP.

How do I prevent dangerous eval - style APIs?

By default script-src (or default-src) blocks eval(), new Function(), and setTimeout(string). Only add 'unsafe-eval' if you have a compelling reason, and pair it with a nonce or hash to limit the impact.

How can I stop my site from being framed (clickjacking protection)?

Add the frame-ancestors directive. To block all framing:

Content - Security - Policy: frame-ancestors 'none';

Older browsers also respect X - Frame - Options, but CSP provides a modern, flexible replacement.

How do I upgrade mixed content automatically?

Include the directive upgrade-insecure-requests (no value). Browsers will rewrite any http: URLs to https: before loading them:

Content - Security - Policy: upgrade-insecure-requests;

This helps during a migration to HTTPS.

How do I get feedback on policy violations?

  1. Deploy a Content - Security - Policy - Report - Only header to log violations without blocking content.
  2. Add a reporting endpoint using report-to (preferred) or the deprecated report-uri directive:
Content - Security - Policy - Report - Only: default-src 'self'; report-to csp-endpoint;
Report-To: {"group":"csp-endpoint","max_age":10886400,"endpoints":[{"url":"https://example.com/csp-report"}]}

Browsers send JSON payloads for each violation, letting you fine - tune the policy.

What are best - practice implementation steps?

  1. Start with a report - only policy - Use a minimal set of directives and monitor reports.
  2. Add nonces or hashes - Replace any 'unsafe-inline' usage.
  3. Gradually tighten - Move from report - only to enforced Content - Security - Policy once no false positives appear.
  4. Include optional hardening - frame-ancestors 'none', upgrade-insecure-requests, and a report-to endpoint.
  5. Automate nonce generation - In server - side code (Node, PHP, etc.) generate a fresh nonce per response and inject it into the header and HTML.

How does CSP complement other security layers?

CSP is one part of a defense - in - depth strategy. It works alongside HTTPS/TLS hardening, secure cookie flags, and server - side input validation. While CSP blocks many client - side injection vectors, it does not replace proper backend security.

Quick example for a typical Node.js Express app

const crypto = require('crypto');
app.use((req, res, next) => {
 const nonce = crypto.randomBytes(16).toString('base64');
 res.locals.nonce = nonce; // use in templates
 const csp = [
 "default-src 'self'",
 `script-src 'self' 'nonce-${nonce}'`,
 "style-src 'self'",
 "img-src 'self' data:" ,
 "object-src 'none'",
 "frame-ancestors 'none'",
 "upgrade-insecure-requests"
 ].join('; ');
 res.setHeader('Content-Security-Policy', csp);
 next();
});

In your HTML template:

<script nonce="{{nonce}}">console.log('Hello');</script>

This enforces a strict CSP while allowing only the scripts you explicitly nonce.

Summary

Implementing CSP starts with delivering the header on every response, defining a sensible set of directives, and using nonces or hashes to allow required inline code. Test with Report - Only, add framing and mixed - content protections, and monitor violation reports to refine the policy. A well - crafted CSP dramatically reduces XSS risk and complements other security measures.

Free security scan

See what's actually exposed on your site.

Decloak's free scan runs in about 15 seconds, no account required, and covers:

  • HTTP/TLS security posture
  • JavaScript CVEs
  • Exposed Supabase/Lovable/Base44 misconfigurations
  • AI-written executive summary