The policy allows inline scripts or styles
What this check looks for
The policy permits code written directly into the page. That is the exact form injected code takes, so this removes most of the policy's value.
Why it matters
Cross-site scripting works by getting code into the page's HTML. A policy that permits inline code permits precisely that, so the protection against the most common attack is switched off.
When the check passes, your report says: “The policy blocks inline scripts and styles”.
What it costs your score
When this check fails it removes 10 points from your Web security score, before the status, confidence and repeat multipliers are applied. Web security carries a weight of 8 in the overall score.
It shares the web-security.csp family ceiling of 30 points: however many findings that family produces, together they cannot remove more than that from Web security. One underlying problem showing up in several places is still one problem.
- Severity
- medium
- Default confidence
- confirmed
- Status when triggered
- warn
- Deduction
- 10 points
- Family cap
- web-security.csp · 30
- Category
- Web security
- Module
- Web security headers
- Fix owned by
- user
- In the ruleset since
- 2026.09
How to fix it
Replace 'unsafe-inline' with a per-request nonce or a hash.
Allowing inline code allows the exact form an injected script takes.
Generate a random nonce per response and put it in the header and on each legitimate
<script>.Add
'strict-dynamic'so scripts those scripts load are trusted without an allow-list.Keep
'unsafe-inline'in the list only as the documented fallback for old browsers — modern ones ignore it once a nonce is present.For styles, hash the small ones or move them into a stylesheet.
How to confirm it worked
curl -sSI https://‹host›/ | grep -i content-security-policy
A named slot like ‹domain› — and the braces left in the configuration below — is filled in with your own values when this rule appears on a report.
Remediation by platform
add_header Content-Security-Policy "script-src 'nonce-‹random›' 'strict-dynamic'; object-src 'none'; base-uri 'none'" always;<IfModule mod_headers.c>
Header always set Content-Security-Policy "script-src 'nonce-‹random›' 'strict-dynamic'; object-src 'none'; base-uri 'none'"
</IfModule>header {
Content-Security-Policy "script-src 'nonce-‹random›' 'strict-dynamic'; object-src 'none'; base-uri 'none'"
}Rules → Overview → Create rule → Response Header Transform Rule → Set static → Content-Security-Policy = script-src 'nonce-‹random›' 'strict-dynamic'; object-src 'none'; base-uri 'none'
(Dashboard path as at 2026-09; Cloudflare reorganised these pages and may again.)The
alwaysflag matters: without it nginx omits the header on error responses, which are exactly the ones an attacker aims for. Note also that anyadd_headerin alocationblock discards everyadd_headerinherited from the server block.Shown because the response identified Apache. Put it in the virtual host rather than .htaccess: .htaccess is re-read on every request, and
Header always setthere runs too late for responses the server generates itself.A Transform Rule adds the header at Cloudflare's edge, so it applies only to responses that reach visitors through Cloudflare. An origin that is reachable directly — by IP, or through a DNS record that is not proxied — still serves the response measured here without it. Setting it at the origin covers both paths.
Technical detail
'unsafe-inline' appears in the effective script-src or style-src.
Note what does *not* trigger this: 'unsafe-inline' alongside a nonce or a hash is a deliberate backwards-compatibility shim, and CSP Level 3 §6.7.3.2 makes browsers that understand nonces ignore it. Only an 'unsafe-inline' with no nonce or hash to supersede it is reported here, because only that one is actually in force.
Standards and references
Test this on your domain
Run the check that produces this finding, on its own, against any domain.
Other web security headers checks
- No Cross-Origin-Embedder-Policy is set
- No Cross-Origin-Opener-Policy is set
- No Cross-Origin-Resource-Policy is set
- No Content Security Policy is enforced
- The policy leaves plugins or the base URL unrestricted
- The Content Security Policy is report-only
- The policy allows eval()
- The policy allows resources from anywhere
- A security header was sent twice with different values
- HSTS max-age is shorter than six months
- HTTP Strict Transport Security is not in force
- HSTS does not cover subdomains