CSP Header Examples: Copy-Paste Content-Security-Policy for Common Stacks
Eight ready-to-adapt CSP header examples for the stacks teams actually ship: marketing sites, SaaS dashboards, checkouts, edge runtimes, and proxies.
Real CSP examples for the stacks teams actually ship.
- Strict and permissive variants per stack.
- Report-only mirrors so you can validate before enforcement.
- report-to JSON config with matching CSP directive.
- Edge-runtime and proxy examples included.
Finding the right csp header examples is often the hardest part of securing your web application. Building a policy from scratch requires deep knowledge of how your framework, third-party scripts, and infrastructure interact. This guide provides copy-pasteable Content-Security-Policy header configurations tailored for the stacks developers actually ship today. Instead of guessing syntax, you can use a CSP generator or start with these baseline templates. Remember to always adapt these examples to your specific domains and validate them thoroughly before enforcing them on production traffic.
How to read these examples
Content Security Policy is not a one-size-fits-all security mechanism. A policy that perfectly secures a static blog will instantly break a complex SaaS dashboard. When reviewing the examples below, keep in mind that they serve as starting points. You will need to replace placeholder domains (like api.example.com) with your actual infrastructure. To ensure your modifications are syntactically correct, run your drafted policy through a reliable CSP checker before deployment.
Strict vs. permissive variants
In the world of CSP, there is a constant tension between security and functionality. A strict policy relies on cryptographic nonces or hashes to explicitly allow individual inline scripts, rejecting everything else. This is the gold standard for mitigating Cross-Site Scripting (XSS). A permissive policy, on the other hand, relies on allowlisting entire domains (e.g., script-src https://cdn.example.com). While easier to implement, permissive policies are vulnerable to bypasses if an attacker can upload a malicious script to the allowed domain or exploit an open redirect. The examples below lean towards strictness where the framework supports it natively, but provide domain-based allowlists for scenarios where strict CSP is technically prohibitive.
Report-only vs. enforcement
Never deploy a new CSP directly in enforcement mode. Doing so is almost guaranteed to break your site for some users. Instead, you should always start with the Content-Security-Policy-Report-Only header. This instructs the browser to monitor traffic and report violations to a specified endpoint without actually blocking any resources. Once you have collected enough data and refined your policy to eliminate false positives, you can switch to the enforcing Content-Security-Policy header. Every example below includes a reporting directive to facilitate this workflow.
Marketing site CSP (static, low risk)
Static marketing sites typically have a small, predictable set of dependencies. They might load a few fonts, a CSS framework, and perhaps a lightweight analytics script. Because there is no user authentication or sensitive data handling, the risk profile is lower, but a strong CSP still prevents defacement and malicious redirects.
Astro / Next.js export / Hugo
For static site generators like Astro, Hugo, or Next.js (using output: 'export'), you often have inline scripts for things like theme toggles or lightweight interactivity. Since generating dynamic nonces at runtime isn’t possible for static files, the best approach is to use a CSP hash for inline scripts and strict domain allowlists for external assets.
Content-Security-Policy:
default-src 'self';
script-src 'self' 'sha256-xyz123...' https://plausible.io;
style-src 'self' 'unsafe-inline' https://fonts.googleapis.com;
font-src 'self' https://fonts.gstatic.com;
img-src 'self' data: https://images.unsplash.com;
connect-src 'self' https://plausible.io;
object-src 'none';
base-uri 'none';
form-action 'self';
frame-ancestors 'none';
report-uri https://api.cspify.io/report/your-project-id;
Key takeaways:
script-src 'sha256-xyz123...': Allows a specific inline script (e.g., a dark mode toggle) by its cryptographic hash. You must compute the SHA-256 hash of the script content and include it here.style-src 'unsafe-inline': Often required for UI component libraries that inject styles dynamically. If possible, extract these to external stylesheets to remove this directive.object-src 'none'andbase-uri 'none': Critical security hygiene to prevent plugin exploitation and base tag hijacking.
SaaS dashboard CSP (auth + third-party widgets)
SaaS dashboards are highly interactive, handle sensitive user data, and frequently integrate with third-party services for support, analytics, and error tracking. This complexity requires a carefully balanced CSP.
React / Vue with Sentry, Hotjar, Stripe
Single Page Applications (SPAs) built with React or Vue often communicate with multiple APIs and load heavy third-party widgets. This example demonstrates how to allowlist essential services while maintaining a strong security posture.
Content-Security-Policy:
default-src 'self';
script-src 'self' https://js.stripe.com https://browser.sentry-cdn.com https://static.hotjar.com;
style-src 'self' 'unsafe-inline' https://fonts.googleapis.com;
font-src 'self' https://fonts.gstatic.com https://script.hotjar.com;
img-src 'self' data: blob: https://*.stripe.com;
connect-src 'self' https://api.yoursaas.com https://api.stripe.com https://*.sentry.io https://*.hotjar.com wss://*.hotjar.com;
frame-src https://js.stripe.com;
worker-src 'self' blob:;
object-src 'none';
base-uri 'self';
form-action 'self';
frame-ancestors 'none';
report-uri https://api.cspify.io/report/your-project-id;
Key takeaways:
connect-src: Extensively configured to allow API calls to your backend (api.yoursaas.com), error reporting (sentry.io), and websocket connections for session recording (wss://*.hotjar.com).frame-src https://js.stripe.com: Required if you are using Stripe Elements, which securely loads payment fields within an iframe.worker-src 'self' blob:: Often needed for performance monitoring tools or complex client-side processing that utilizes Web Workers.
Ecommerce checkout CSP (Stripe / Adyen / Klarna)
Ecommerce checkouts represent the highest risk area of a web application. A successful XSS attack here can lead directly to credit card skimming (Magecart attacks). The CSP must be incredibly strict, allowing only the absolute minimum required to process the transaction.
Content-Security-Policy:
default-src 'self';
script-src 'self' https://js.stripe.com https://www.googletagmanager.com;
style-src 'self' 'unsafe-inline';
img-src 'self' data: https://www.google-analytics.com https://*.stripe.com;
connect-src 'self' https://api.stripe.com https://www.google-analytics.com;
frame-src https://js.stripe.com https://hooks.stripe.com;
object-src 'none';
base-uri 'none';
form-action 'self' https://checkout.stripe.com;
frame-ancestors 'none';
report-uri https://api.cspify.io/report/your-project-id;
Key takeaways:
- Minimal third-party scripts: Only the payment gateway (Stripe) and essential analytics (Google Analytics) are permitted. Marketing pixels, chat widgets, and A/B testing tools should be strictly excluded from the checkout flow to minimize the attack surface.
form-action: Restricted to'self'and the payment provider to prevent attackers from hijacking form submissions and stealing credentials or payment details.frame-ancestors 'none': Prevents clickjacking attacks by ensuring your checkout page cannot be embedded in an iframe on a malicious site.
CSP for Next.js (App Router)
Next.js App Router provides powerful server-side capabilities, making it the perfect candidate for a strict, nonce-based CSP. By generating a unique CSP nonce for every request, you can completely eliminate the need for 'unsafe-inline' in your script-src.
Middleware that injects nonce per request
The recommended approach, as detailed in the Next.js Security Headers docs, is to use Next.js Middleware to generate the nonce, construct the CSP header, and pass both down to the application.
// middleware.ts
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'
export function middleware(request: NextRequest) {
const nonce = Buffer.from(crypto.randomUUID()).toString('base64')
const cspHeader = `
default-src 'self';
script-src 'self' 'nonce-${nonce}' 'strict-dynamic';
style-src 'self' 'unsafe-inline';
img-src 'self' blob: data:;
font-src 'self';
object-src 'none';
base-uri 'self';
form-action 'self';
frame-ancestors 'none';
report-uri https://api.cspify.io/report/your-project-id;
`
const contentSecurityPolicyHeaderValue = cspHeader
.replace(/\s{2,}/g, ' ')
.trim()
const requestHeaders = new Headers(request.headers)
requestHeaders.set('x-nonce', nonce)
requestHeaders.set(
'Content-Security-Policy',
contentSecurityPolicyHeaderValue
)
const response = NextResponse.next({
request: {
headers: requestHeaders,
},
})
response.headers.set(
'Content-Security-Policy',
contentSecurityPolicyHeaderValue
)
return response
}
export const config = {
matcher: [
'/((?!api|_next/static|_next/image|favicon.ico).*)',
],
}
Key takeaways:
'nonce-${nonce}': A cryptographically secure random string generated on every request. Only<script>tags bearing this exact nonce will be executed.'strict-dynamic': An advanced directive that tells the browser to trust scripts dynamically loaded by a nonced script. This makes integrating complex third-party libraries much easier without compromising security.
CSP at the edge: Cloudflare Workers
If you cannot modify your application code directly, or if you want to enforce a baseline security policy across multiple disparate applications, setting the CSP at the edge is a highly effective strategy. Cloudflare Workers allow you to intercept and modify HTTP responses before they reach the user.
// worker.js
export default {
async fetch(request, env, ctx) {
const response = await fetch(request);
// Clone the response so we can modify headers
const newResponse = new Response(response.body, response);
const csp = [
"default-src 'self'",
"script-src 'self' https://static.cloudflareinsights.com",
"style-src 'self' 'unsafe-inline'",
"img-src 'self' data:",
"connect-src 'self' https://cloudflareinsights.com",
"object-src 'none'",
"base-uri 'none'",
"frame-ancestors 'none'",
"report-uri https://api.cspify.io/report/your-project-id"
].join('; ');
newResponse.headers.set('Content-Security-Policy', csp);
// Optional: Add other security headers
newResponse.headers.set('X-Content-Type-Options', 'nosniff');
newResponse.headers.set('Referrer-Policy', 'strict-origin-when-cross-origin');
return newResponse;
},
};
Key takeaways:
- Centralized management: Managing CSP at the edge ensures that all traffic, regardless of the underlying origin server, receives the correct security headers.
- Performance: Edge execution adds negligible latency while providing robust protection.
- Flexibility: You can easily implement logic to serve different CSPs based on the request path, user agent, or environment variables.
CSP at the proxy: Nginx and Caddy
For traditional deployments involving virtual machines or bare-metal servers, the reverse proxy is the ideal place to inject security headers. Nginx and Caddy both make this straightforward.
Nginx
In Nginx, use the add_header directive within your server or location block.
server {
listen 443 ssl;
server_name example.com;
# Other SSL and server configurations...
set $csp "default-src 'self'; ";
set $csp "${csp}script-src 'self' https://apis.google.com; ";
set $csp "${csp}style-src 'self' 'unsafe-inline'; ";
set $csp "${csp}img-src 'self' data:; ";
set $csp "${csp}font-src 'self'; ";
set $csp "${csp}object-src 'none'; ";
set $csp "${csp}base-uri 'none'; ";
set $csp "${csp}form-action 'self'; ";
set $csp "${csp}frame-ancestors 'none'; ";
set $csp "${csp}report-uri https://api.cspify.io/report/your-project-id;";
add_header Content-Security-Policy $csp always;
location / {
proxy_pass http://localhost:3000;
# Proxy configurations...
}
}
Key takeaways:
always: This flag is crucial. Without it, Nginx will not send the CSP header on error responses (like 404 or 500 pages), leaving those pages vulnerable to XSS.- Variable concatenation: Breaking the CSP string into variables makes it significantly easier to read and maintain in the Nginx configuration file.
CSP for Express / Fastify
If you are building a Node.js backend serving HTML directly, or an API that needs to protect its endpoints, middleware libraries are the standard approach. For Express, Helmet.js is the industry standard.
const express = require('express');
const helmet = require('helmet');
const app = express();
app.use(
helmet({
contentSecurityPolicy: {
directives: {
defaultSrc: ["'self'"],
scriptSrc: ["'self'", "https://cdn.jsdelivr.net"],
styleSrc: ["'self'", "'unsafe-inline'", "https://fonts.googleapis.com"],
fontSrc: ["'self'", "https://fonts.gstatic.com"],
imgSrc: ["'self'", "data:", "https://images.unsplash.com"],
connectSrc: ["'self'", "https://api.example.com"],
objectSrc: ["'none'"],
upgradeInsecureRequests: [],
reportUri: "https://api.cspify.io/report/your-project-id",
},
},
})
);
app.get('/', (req, res) => {
res.send('<h1>Secure Express App</h1>');
});
app.listen(3000, () => {
console.log('Server running on port 3000');
});
Key takeaways:
- Helmet.js defaults: Helmet provides sensible defaults for many security headers, including CSP. Configuring it via the
directivesobject is clean and type-safe (if using TypeScript). upgradeInsecureRequests: Instructs the browser to automatically upgrade any HTTP requests to HTTPS, preventing mixed content warnings and securing data in transit.
Reporting: report-uri and report-to
Visibility is the cornerstone of effective CSP management. Without reporting, you are flying blind. The older report-uri directive is widely supported, but the modern standard is report-to, which utilizes the Reporting API. Because browser support for report-to is still inconsistent (Safari notably lacks support), you must implement both.
To use report-to, you first define a Report-To HTTP header containing a JSON configuration, and then reference that configuration group in your CSP.
Report-To: {"group":"csp-endpoint","max_age":10886400,"endpoints":[{"url":"https://api.cspify.io/report/your-project-id"}]}
Content-Security-Policy-Report-Only:
default-src 'self';
script-src 'self';
object-src 'none';
report-uri https://api.cspify.io/report/your-project-id;
report-to csp-endpoint;
Key takeaways:
- Always use report-only mode first: Notice the use of
Content-Security-Policy-Report-Only. This ensures that violations are logged to your endpoint without breaking the user experience. - Fallback mechanism: Browsers that understand
report-towill use thecsp-endpointgroup. Older browsers will ignorereport-toand fall back to thereport-uridirective.
Frequently asked questions
Review these common questions to ensure your implementation is robust and secure.
What’s the simplest valid CSP header?
The simplest valid CSP header is default-src 'self';. This restricts all resources (scripts, images, styles, fonts, etc.) to the same origin as the document. While highly secure, it often breaks modern web applications that rely on third-party fonts, analytics, or CDNs, which is why most sites require a more tailored policy.
How do I write a CSP for Next.js App Router?
In Next.js App Router, the best practice is to use Middleware (middleware.ts) to generate a unique cryptographic nonce per request. You inject this nonce into a Content-Security-Policy header, pass it to the request headers, and read it in your root layout to apply to <script> tags.
How do I set CSP in Nginx?
You can set a CSP in Nginx using the add_header directive within your server or location block. For example: add_header Content-Security-Policy "default-src 'self';" always;. The always flag ensures the header is sent even on error pages.
How do I set CSP at Cloudflare?
You can set a CSP at Cloudflare using Cloudflare Workers or Cloudflare Transform Rules. With a Worker, you intercept the response and use response.headers.set('Content-Security-Policy', '...') before returning it to the client.
Can I use the same CSP across staging and production?
Usually, no. Staging environments often require different CSP directives, such as allowing hot-module replacement (HMR) tools, staging-specific API endpoints, or unminified scripts. It’s recommended to maintain environment-specific CSP configurations.
How do I deal with report-to browser support?
Because report-to is not universally supported (notably lacking in Safari), you should always include the older report-uri directive alongside report-to. Browsers that support report-to will prioritize it, while older browsers and Safari will fall back to report-uri.
Validate your copied CSP before it hits production
Copying a CSP header example is only the first step. The real challenge is ensuring that the policy doesn’t inadvertently block critical functionality on your live site. Before switching to enforcement mode, you need visibility into what your policy would block.
Try CSPify free to instantly deploy an endpoint for your report-uri and report-to directives. Watch your violation reports stream in, identify false positives, and refine your policy with confidence. Need help building your initial policy from scratch? Open the CSP Builder to generate a custom, secure baseline in seconds.
Validate your copied CSP before it hits production
Start free and watch what your CSP would block in report-only mode.