Content-Security-Policy Generator
Build a strong CSP header with our visual editor. Start with a preset for your platform, customize per directive, and copy-paste the result into Nginx, Apache, Express, Next.js, Vercel, or Django. Free, no signup required.
CSP is the single most effective HTTP header against Cross-Site Scripting (XSS) attacks. It tells the browser exactly which sources can load scripts, styles, and other resources. Anything not in the policy gets blocked.
Quick presets
Start with a preset tuned for your stack, then customize. Each preset balances security with compatibility for the platform.
Directives
Generated CSP header
default-src 'self'; script-src 'self'; style-src 'self'; img-src 'self' data:; font-src 'self'; connect-src 'self'; frame-src 'none'; media-src 'self'; object-src 'none'; base-uri 'self'; form-action 'self'; frame-ancestors 'none'
Copy-paste examples
add_header Content-Security-Policy "default-src 'self'; script-src 'self'; style-src 'self'; img-src 'self' data:; font-src 'self'; connect-src 'self'; frame-src 'none'; media-src 'self'; object-src 'none'; base-uri 'self'; form-action 'self'; frame-ancestors 'none'" always;
Header always set Content-Security-Policy "default-src 'self'; script-src 'self'; style-src 'self'; img-src 'self' data:; font-src 'self'; connect-src 'self'; frame-src 'none'; media-src 'self'; object-src 'none'; base-uri 'self'; form-action 'self'; frame-ancestors 'none'"
app.use((req, res, next) => {
res.setHeader(
'Content-Security-Policy',
'default-src 'self'; script-src 'self'; style-src 'self'; img-src 'self' data:; font-src 'self'; connect-src 'self'; frame-src 'none'; media-src 'self'; object-src 'none'; base-uri 'self'; form-action 'self'; frame-ancestors 'none''
);
next();
});const securityHeaders = [
{
key: 'Content-Security-Policy',
value: `default-src 'self'; script-src 'self'; style-src 'self'; img-src 'self' data:; font-src 'self'; connect-src 'self'; frame-src 'none'; media-src 'self'; object-src 'none'; base-uri 'self'; form-action 'self'; frame-ancestors 'none'`
}
];
module.exports = {
async headers() {
return [{ source: '/(.*)', headers: securityHeaders }];
}
};{
"headers": [{
"source": "/(.*)",
"headers": [{
"key": "Content-Security-Policy",
"value": "default-src 'self'; script-src 'self'; style-src 'self'; img-src 'self' data:; font-src 'self'; connect-src 'self'; frame-src 'none'; media-src 'self'; object-src 'none'; base-uri 'self'; form-action 'self'; frame-ancestors 'none'"
}]
}]
}# settings.py. Use django-csp:
# pip install django-csp
CSP_DEFAULT_SRC = ("'self'",)
CSP_SCRIPT_SRC = ("'self'",)
CSP_OBJECT_SRC = ("'none'",)Replace Content-Security-Policy with Content-Security-Policy-Report-Only to log violations without blocking anything. Monitor your browser console or a reporting endpoint to find resources that need to be added before switching to enforcement mode.
What is Content-Security-Policy?
Content-Security-Policy (CSP) is an HTTP response header that creates an allowlist of trusted sources for your web page. When a browser loads your page and sees the CSP header, it enforces the policy: any script, stylesheet, image, font, or other resource that doesn't match an allowed source is blocked from loading.
CSP was designed to stop Cross-Site Scripting (XSS). Classified as OWASP Top 10 A03:2021, the most common web vulnerability. XSS attacks inject malicious JavaScript into your page. Through form fields, URL parameters, or stored data. Without CSP, the browser executes the injected script because it can't distinguish it from your legitimate code. With CSP, the browser checks the script's origin against your policy and blocks it if it's not on the allowlist.
CSP also protects against clickjacking (via frame-ancestors. See W3C CSP Level 3 spec), data exfiltration (via connect-src), form hijacking (via form-action), and plugin-based attacks (via object-src). A single header blocks entire categories of attacks that would otherwise require application-level fixes.
How CSP works. Step by step
CSP directive reference
Each directive controls a specific resource type. If a directive is not set, the browser falls back to default-src. Setting default-src 'self' as your baseline and overriding per directive is the recommended approach.
| Directive | Controls | Recommended |
|---|---|---|
| default-src | Fallback for all resource types | 'self' |
| script-src | JavaScript execution | 'self' (use nonces for inline) |
| style-src | CSS loading | 'self' (inline OK if needed) |
| img-src | Image loading | 'self' data: |
| font-src | Web font loading | 'self' |
| connect-src | fetch, XHR, WebSocket | 'self' + your API |
| frame-src | iframe embedding | 'none' |
| object-src | Plugins (object, embed) | 'none' (always) |
| base-uri | base tag URL | 'self' |
| form-action | Form submission targets | 'self' |
| frame-ancestors | Who can embed your page | 'none' |
| media-src | Audio and video | 'self' |
CSP best practices
Common CSP mistakes
| Mistake | Why it's bad | Fix |
|---|---|---|
| script-src with unsafe keywords | Allows all inline scripts. CSP is effectively disabled for XSS | Use nonces or hashes instead |
| default-src * | Allows loading from any origin. No protection at all | Use 'self' and add specific domains |
| Missing object-src | Falls back to default-src, may allow plugin execution | Always set object-src 'none' |
| Using http: sources | Allows mixed content, enables MITM attacks | Only allow https: sources |
| Too many wildcards | *.example.com allows any subdomain including attacker-controlled ones | List specific subdomains |
| Forgetting connect-src | Falls back to default-src, may block your API calls | Add your API domain to connect-src |
CSP implementation by framework
Next.js (App Router)
Next.js supports CSP via middleware for dynamic nonce generation, or via next.config.js for static policies. Use middleware if you need nonces for inline scripts.
// middleware.ts
import { NextResponse } from 'next/server';
export function middleware(request) {
const nonce = Buffer.from(
crypto.randomUUID()
).toString('base64');
const csp = [
"default-src 'self'",
`script-src 'self' 'nonce-${nonce}'`,
"style-src 'self' 'unsafe-inline'",
"img-src 'self' data:",
"object-src 'none'",
"base-uri 'self'",
"frame-ancestors 'none'"
].join('; ');
const response = NextResponse.next();
response.headers.set(
'Content-Security-Policy', csp
);
response.headers.set('x-nonce', nonce);
return response;
}Laravel
Add CSP via middleware or use the spatie/laravel-csp package for a structured approach.
// app/Http/Middleware/CspHeader.php
public function handle($request, Closure $next)
{
$response = $next($request);
$response->headers->set(
'Content-Security-Policy',
"default-src 'self'; "
. "script-src 'self'; "
. "object-src 'none'; "
. "frame-ancestors 'none'"
);
return $response;
}Django
Use django-csp for declarative CSP or set headers in custom middleware.
# pip install django-csp
# settings.py
MIDDLEWARE = [
'csp.middleware.CSPMiddleware',
# ...
]
CSP_DEFAULT_SRC = ("'self'",)
CSP_SCRIPT_SRC = ("'self'",)
CSP_STYLE_SRC = ("'self'", "'unsafe-inline'")
CSP_IMG_SRC = ("'self'", "data:")
CSP_OBJECT_SRC = ("'none'",)
CSP_FRAME_ANCESTORS = ("'none'",)
CSP_BASE_URI = ("'self'",)Ruby on Rails
Rails has built-in CSP support via the content_security_policy initializer.
# config/initializers/content_security_policy.rb
Rails.application.configure do
config.content_security_policy do |policy|
policy.default_src :self
policy.script_src :self
policy.style_src :self, :unsafe_inline
policy.img_src :self, :data
policy.object_src :none
policy.frame_ancestors :none
policy.base_uri :self
end
endCloudflare Workers
Add CSP at the edge for any origin behind Cloudflare.
addEventListener('fetch', event => {
event.respondWith(handleRequest(event.request));
});
async function handleRequest(request) {
const response = await fetch(request);
const newResponse = new Response(
response.body, response
);
newResponse.headers.set(
'Content-Security-Policy',
"default-src 'self'; "
+ "script-src 'self'; "
+ "object-src 'none'"
);
return newResponse;
}Frequently asked questions
What is a Content-Security-Policy header?+
Content-Security-Policy (CSP) is an HTTP response header that tells the browser which sources are allowed to load resources like scripts, styles, images, and fonts. It acts as an allowlist. Anything not explicitly permitted is blocked. CSP is the single most effective defense against Cross-Site Scripting (XSS) attacks.
How does CSP prevent XSS attacks?+
XSS attacks work by injecting malicious scripts into your page. CSP blocks these scripts because the attacker's origin is not in your allowlist. Even if an attacker manages to inject a script tag, the browser refuses to execute it because the source violates the policy. This makes CSP a critical layer of defense beyond input sanitization.
What does 'unsafe-inline' mean and should I use it?+
'unsafe-inline' allows execution of inline script tags and inline event handlers (onclick, onerror, etc.). This significantly weakens CSP because attackers who can inject HTML can also inject inline scripts. Avoid it for script-src whenever possible. Use nonces or hashes instead. For style-src, 'unsafe-inline' is more common because many CSS frameworks rely on inline styles.
What is the difference between CSP and X-Frame-Options?+
X-Frame-Options only controls whether your page can be framed (embedded in an iframe). CSP's frame-ancestors directive does the same thing but with more flexibility. You can allow specific origins instead of just DENY or SAMEORIGIN. CSP also covers scripts, styles, images, fonts, connections, and many other resource types. Use both for maximum browser compatibility.
How do I test CSP without breaking my site?+
Use Content-Security-Policy-Report-Only instead of Content-Security-Policy. This tells the browser to report violations without actually blocking anything. Add a report-uri or report-to directive to collect violation reports. Monitor the reports, fix any legitimate resources that get flagged, then switch to enforcing mode.
Why does my site break after adding CSP?+
CSP blocks any resource not explicitly allowed. Common causes: inline scripts or styles (need 'unsafe-inline' or nonces), third-party analytics scripts (add their domain to script-src), Google Fonts (add fonts.googleapis.com to style-src and fonts.gstatic.com to font-src), CDN-hosted libraries (add the CDN domain to script-src). Start with Report-Only mode to identify what needs to be allowed.
What is a CSP nonce and how do I use it?+
A nonce is a random, single-use token generated on each page load. You add it to your CSP header (script-src 'nonce-abc123') and to each inline script tag. The browser only executes scripts with a matching nonce. This is safer than 'unsafe-inline' because an attacker cannot guess the nonce. Your server must generate a new nonce for every response.
Do I need CSP if I already sanitize user input?+
Yes. Input sanitization is important but not foolproof. Bypasses are discovered regularly. CSP is a defense-in-depth layer. Even if sanitization fails and an attacker injects a script, CSP blocks it from executing. Think of CSP as your seatbelt: you still drive carefully, but the seatbelt saves you when something goes wrong.
Which CSP directives should I always set?+
At minimum: default-src 'self' (baseline), script-src 'self' (block injected scripts), object-src 'none' (block plugins), base-uri 'self' (prevent base tag hijacking), and frame-ancestors 'none' (prevent clickjacking). These five directives block the most common attack vectors with minimal compatibility impact.
How do I add CSP to my Next.js or Vercel project?+
In Next.js, add a headers() function in next.config.js or use middleware. For Vercel, add a headers array in vercel.json. You can also set CSP in a custom middleware.ts file for dynamic nonce generation. Our generator provides copy-paste code for both approaches.
Related resources
Test your CSP on a live site
Use our header checker to verify your CSP is deployed correctly, or run a full scan covering 150+ security checks.
Run Full Security Scan