dotvitals

Loading the list of pages…

↑↓ to moveEnter to openEsc to close

The policy allows inline scripts to run

Updated

MediumConfirmedweb.security-headers.csp-unsafe-inline

38% of the 238 domains we could check get a warning for this. Sample: the first 1,000 domains by rank in the Majestic Million, checked on 2026-10-12. How we measured

What this check looks for

The policy lets the browser run script 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 script into the page's HTML. A policy that permits inline script 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”.

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 the whole score is calculated

How to fix it

Allow inline script only by a per-request nonce or a hash — not by 'unsafe-inline', and not by leaving scripts ungoverned.

Allowing inline script allows the exact form an injected script takes.

  1. Generate a random nonce per response and put it in the header and on each legitimate <script>.

  2. Add 'strict-dynamic' so scripts those scripts load are trusted without an allow-list.

  3. Keep 'unsafe-inline' in the list only as the documented fallback for old browsers — modern ones ignore it once a nonce is present.

  4. Move inline event handlers such as onclick= into script: a nonce cannot be put on an attribute.

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

nginx
add_header Content-Security-Policy "default-src 'self'; script-src 'nonce-‹random›' 'strict-dynamic'; object-src 'none'; base-uri 'none'" always;
Apache
<IfModule mod_headers.c>
	Header always set Content-Security-Policy "default-src 'self'; script-src 'nonce-‹random›' 'strict-dynamic'; object-src 'none'; base-uri 'none'"
</IfModule>
Caddy
header {
	Content-Security-Policy "default-src 'self'; script-src 'nonce-‹random›' 'strict-dynamic'; object-src 'none'; base-uri 'none'"
}
Cloudflare
Rules → Overview → Create rule → Response Header Transform Rule → Set static → Content-Security-Policy = default-src 'self'; 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 always flag matters: without it nginx omits the header on error responses, which are exactly the ones an attacker aims for. Note also that any add_header in a location block discards every add_header inherited 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 set there 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

‹detail›.

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. A policy that sets none of script-src-elem, script-src-attr, script-src or default-src governs no inline script at all, and blocks none: that is reported here as a note rather than a deduction, because csp-missing already fails the policy for it and the gap is charged once. This rule is about scripts alone: 'unsafe-inline' on the style side is reported by its own, lower-priced rule, because a style cannot run code.

Standards and references

Test this on your domain

Run the check that produces this finding, on its own, against any domain.

Open the web security headers checkerBuild the fix