Content Security Policy (CSP) is one of the most powerful tools for protecting websites against cross-site scripting (XSS) and data injection attacks. But building a correct CSP header can be tricky. This guide provides real-world examples for common website types, with each directive explained so you can adapt them to your needs.
How CSP Works
CSP tells the browser which sources it is allowed to load resources from — scripts, styles, images, fonts, frames, and more. When a page loads, the browser enforces the policy and blocks any resource that is not explicitly permitted. This stops attackers from injecting malicious scripts even if they find an XSS vulnerability.
CSP is delivered as an HTTP response header or as a <meta> tag (with limited functionality):
Content-Security-Policy: default-src 'self'; script-src 'self' https://cdn.example.com; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' https://fonts.gstatic.com; frame-ancestors 'none';CSP Directives Reference
| Directive | Controls |
|---|---|
default-src | Fallback for all resource types not explicitly specified |
script-src | JavaScript sources |
style-src | CSS stylesheet sources |
img-src | Image sources |
font-src | Web font sources |
connect-src | API fetch/XHR/WebSocket connections |
frame-src | Sources that can be embedded in iframes |
frame-ancestors | Which pages can embed this page in an iframe |
form-action | URLs to which forms can submit |
base-uri | Restricts the base URL for relative URLs |
object-src | Plugin sources (Flash, Java applets). Always set to 'none'. |
upgrade-insecure-requests | Upgrades HTTP subresources to HTTPS automatically |
Example 1: Strict Static Website
For a simple static site with no external scripts and inline styles avoided:
Content-Security-Policy:
default-src 'none';
script-src 'self';
style-src 'self';
img-src 'self' data:;
font-src 'self';
connect-src 'self';
frame-ancestors 'none';
base-uri 'self';
form-action 'self';This is the most restrictive policy and the ideal baseline. It blocks everything not explicitly permitted and prevents your page from being framed by any other site (frame-ancestors 'none').
Example 2: Site with Google Fonts and Google Analytics
Most marketing sites use Google Fonts and Google Analytics or Tag Manager:
Content-Security-Policy:
default-src 'self';
script-src 'self' https://www.googletagmanager.com https://www.google-analytics.com;
style-src 'self' 'unsafe-inline' https://fonts.googleapis.com;
img-src 'self' data: https://www.google-analytics.com https://www.googletagmanager.com;
font-src 'self' https://fonts.gstatic.com;
connect-src 'self' https://www.google-analytics.com;
frame-ancestors 'none';
base-uri 'self';'unsafe-inline' is required for style-src. Avoiding inline styles in your own code is still best practice.Example 3: WordPress Site
WordPress typically requires more permissive policies due to inline scripts in the admin bar, plugins generating inline styles, and multiple third-party integrations:
Content-Security-Policy:
default-src 'self';
script-src 'self' 'unsafe-inline' 'unsafe-eval' https://ajax.googleapis.com https://www.google.com https://www.gstatic.com;
style-src 'self' 'unsafe-inline' https://fonts.googleapis.com;
img-src 'self' data: https: blob:;
font-src 'self' data: https://fonts.gstatic.com;
connect-src 'self' https://www.google-analytics.com https://woocommerce.com;
frame-src 'self' https://www.google.com;
frame-ancestors 'self';
base-uri 'self';Content-Security-Policy-Report-Only) to identify violations before enforcing.Example 4: Next.js / React SPA
For Next.js applications, you can use nonces to allow inline scripts securely without 'unsafe-inline':
// next.config.mjs — using nonces for strict CSP
const nonce = Buffer.from(crypto.randomUUID()).toString('base64');
const cspHeader = `
default-src 'self';
script-src 'self' 'nonce-${nonce}' 'strict-dynamic';
style-src 'self' 'nonce-${nonce}';
img-src 'self' blob: data: https:;
font-src 'self';
connect-src 'self' https://api.example.com;
frame-ancestors 'none';
base-uri 'self';
object-src 'none';
`;Example 5: API Server
API servers that do not serve HTML should use a minimal CSP:
Content-Security-Policy: default-src 'none'; frame-ancestors 'none';This prevents any resource loading and ensures the API responses cannot be framed by third-party pages.
Report-Only Mode: Testing CSP Without Breaking Things
The Content-Security-Policy-Report-Only header lets you test a policy without enforcing it. Violations are reported to a specified endpoint but the page still loads normally:
Content-Security-Policy-Report-Only:
default-src 'self';
script-src 'self';
report-uri https://csp-reports.example.com/collect;Use report-only mode to identify all resource sources your site uses before switching to enforcing mode. This prevents you from accidentally breaking functionality.
Checking Your CSP Header
Use the ShowDNS CSP Checker to inspect your Content-Security-Policy header and identify missing directives or overly permissive settings. Also check your full security posture with the Security Headers tool.
Frequently Asked Questions
What does 'self' mean in CSP?
'self' refers to the same origin as the page — the same scheme, host, and port. Scripts and styles loaded from 'self' are allowed. Note that subdomains are not considered the same origin.
Can I use CSP with a CDN?
Yes. Add the CDN's domain to the appropriate directive. For example: script-src 'self' https://cdn.example.com. If your CDN uses a wildcard subdomain, you can use https://*.cdn.example.com, but be careful — this allows any subdomain of that CDN to load scripts.
Why is unsafe-inline bad?
'unsafe-inline' allows inline <script> and <style> tags, as well as JavaScript event handlers in HTML. This defeats one of the main goals of CSP — preventing XSS — because an attacker who can inject HTML can inject inline scripts.
How do I deal with CSP violations in production?
Add a report-uri or report-to directive to collect violation reports. Services like Report URI or your own endpoint can aggregate these and help you identify what to add to your policy or what security issues exist.