The fix, in one snippet
Content-Security-Policy: default-src 'self'; script-src 'self'; object-src 'none'; frame-ancestors 'none'; base-uri 'none'
Illustrative values. Change the paths, hostnames and options to match your own site before using it.
The sections below explain what is tested, why it matters and the alternatives.
What we test
Scan.now reads the Content-Security-Policy header from the HTTPS response to /. If there is no header, it also looks for a <meta http-equiv="Content-Security-Policy"> element in the HTML, which browsers honour for most directives (but not frame-ancestors, report-uri or sandbox). The check passes when an enforced policy exists that constrains script execution through script-src or a default-src fallback. It fails when there is no policy at all, and it also fails, with an explanatory note, when only Content-Security-Policy-Report-Only is present, because a report-only policy blocks nothing. The quality of the directives (for example 'unsafe-inline' or wildcards) is assessed separately in csp-weak-directives, and clickjacking protection via frame-ancestors in x-frame-options.
Why it matters
Cross-site scripting remains one of the most common web vulnerabilities (OWASP Top 10:2021 folds it into A03 Injection). Output encoding is the primary defence, but a single missed sink in a template, a third-party widget or an old library is enough. A Content Security Policy is the second layer: even when an attacker manages to inject <script>, the browser refuses to execute anything that is not from an allowed source or carrying the right nonce. A realistic scenario is a comment field that escapes most characters but not an attribute context; without CSP the injected handler steals session tokens or silently rewrites a payment form (the Magecart pattern). CSP also governs where forms may post, which origins may frame the page, and whether plugins load. Our CSP guide and XSS guide go deeper.
How to fix it
Start in report-only mode, watch the reports for a few days, then enforce. A nonce-based "strict" policy is the modern recommendation because it does not depend on maintaining a host allowlist:
Content-Security-Policy: script-src 'nonce-{RANDOM}' 'strict-dynamic'; object-src 'none'; base-uri 'none'; frame-ancestors 'self'; form-action 'self'; upgrade-insecure-requests
The nonce must be fresh per response, so it is generated by the application rather than the web server. Express with Helmet:
app.use((req, res, next) => { res.locals.nonce = crypto.randomBytes(16).toString('base64'); next(); });
app.use(helmet.contentSecurityPolicy({
directives: {
scriptSrc: [(req, res) => `'nonce-${res.locals.nonce}'`, "'strict-dynamic'"],
objectSrc: ["'none'"], baseUri: ["'none'"], frameAncestors: ["'self'"],
},
}));
Static sites without inline scripts can use a simple allowlist set at the server. nginx:
add_header Content-Security-Policy "default-src 'self'; script-src 'self'; object-src 'none'; base-uri 'none'; frame-ancestors 'self'" always;
Apache: Header always set Content-Security-Policy "...". On Cloudflare, a Transform Rule (Rules > Transform Rules > Modify Response Header) adds the header at the edge. For rollout, send the same policy as Content-Security-Policy-Report-Only with a report-to directive and a Reporting-Endpoints header, fix what the reports show, then switch header names.
Where this fits
Content-Security-Policy missing is check 4 of 13 that the website vulnerability scanner runs under http security headers, ordered the way they are worth fixing. That ordering is the point: Fixing this one while the check above it still fails buys less than it looks like.
Fix this one first
Above it in the same category sits Content-Security-Policy is weak (medium), where a Content-Security-Policy exists but contains directives that let injected script run anyway: 'unsafe-inline' without nonces, 'unsafe-eval', wildcards, data: URIs, or missing object-src and base-uri. An attacker who has that does not need this, so it is the better use of the same hour.
What fixing this still leaves open
Content-Security-Policy missing closes one route in. Immediately below it: Cross-Origin-Opener-Policy, where the page does not set Cross-Origin-Opener-Policy, so windows it opens, or that open it, from other origins keep a reference to it and share its browsing context group; Permissions-Policy, where no Permissions-Policy header restricts powerful browser features; Referrer-Policy, where no Referrer-Policy is set, or it is set to a value that sends full URLs to other sites.
Found in the same scan
The website vulnerability scanner reports this alongside checks from other categories that are at least as serious, including Certificate chain and hostname validation, where the certificate presented for this hostname did not validate: The chain does not reach a trusted root, an intermediate is missing, the name does not match, or the certificate is self-signed or expired, and Exposed .env configuration file, where a .env configuration file is served from the web root. A single run of website vulnerability scanner answers all of them at once.
The first few lines
You are a senior web engineer. I ran a security and SEO scanner against my site and it reported the finding below. Fix it properly rather than suppressing the symptom.
Finding: Content-Security-Policy missing (medium severity)
Scanner check id: content-security-policy
The rest of this prompt names the pages and line numbers we found the problem on, the configuration to change, and the constraints a good answer has to respect. It is free, it just needs an account so the work is not scraped wholesale.
Sign in with GoogleSigning in is free and takes one click. We store your email address and nothing else.
References
Related guides
9 min read · Updated Sep 16, 2026
Content Security Policy (CSP): A Practical Guide to Writing One That Works
A Content Security Policy tells the browser which scripts, styles and resources a page may load, which defeats most cross-site...
Read the guide
8 min read · Updated Sep 19, 2026
Cross-Site Scripting (XSS) Explained: Reflected, Stored, DOM-Based and How to Prevent It
XSS lets an attacker run their own script in your users' browsers. The three types, what an attacker does with it and the layered...
Read the guide