If your Content Security Policy includes 'unsafe-inline' in the script-src directive, you don't have a Content Security Policy. You have a header that makes security auditors feel good while doing nothing to stop cross-site scripting.
That's not an exaggeration. The entire point of CSP for scripts is to prevent the browser from executing injected code. 'unsafe-inline' tells the browser to execute any inline script it finds. An attacker who injects <script>steal(document.cookie)</script> into your page wins, because your CSP explicitly allows it.
The three layers of strict CSP
Nonce-based scripts. Instead of allowing all inline scripts, you generate a random nonce on each page load and add it to both the CSP header (script-src 'nonce-abc123') and each legitimate script tag (<script nonce="abc123">). Injected scripts won't have the nonce. The browser blocks them.
strict-dynamic. Once you have nonces, 'strict-dynamic' tells the browser that any script loaded by a nonced script is also trusted. This means you don't need to list every CDN domain in your CSP. Your nonced bootstrap script can load whatever it needs, but an attacker's injected script still can't execute.
Trusted Types. This is the newest layer. require-trusted-types-for 'script' tells the browser to block DOM XSS sinks like innerHTML, document.write, and eval unless the input has been explicitly sanitized through a Trusted Types policy. Even if an attacker gets past your CSP, Trusted Types blocks the most common DOM manipulation attacks.
Why most sites don't use any of these
Because strict CSP is hard. Adding nonces requires server-side rendering or edge-function injection on every page load. strict-dynamic requires understanding your script dependency chain. Trusted Types requires auditing every line of JavaScript that touches the DOM.
And because 'unsafe-inline' plus a list of CDN domains passes most automated security scanners. The scanner sees a CSP header, checks the box, and moves on. Nobody manually verifies that the policy actually prevents anything.
What the tool checks
The CSP Strictness Audit fetches your page and its CSP, then evaluates six dimensions:
- Whether nonces or hashes are used instead of
'unsafe-inline' - Whether
'strict-dynamic'is present - Whether
'unsafe-eval'is absent - Whether
report-toorreport-uriis configured so you know when violations happen - Whether Trusted Types enforcement is enabled
- Whether wildcard sources are present and how broad they are
The result is a strictness score with specific, actionable findings per dimension.
Getting these right from the start is easier than retrofitting. If you're setting up new sites regularly, The $97 Launch walks through the security headers to ship with on day one.
Fact-check notes and sources
- Nonce-based CSP: Google CSP best practices
- strict-dynamic specification: W3C CSP Level 3, Section 8.2
- Trusted Types: web.dev/trusted-types
'unsafe-inline'negates CSP script protection: MDN CSP reference
Related reading
- CSP allowlist completeness
- Inline event handlers and CSP
- Trusted Types and DOM XSS
- API secret leakage in client-side code
This post is informational, not security-consulting advice. Mentions of Google, W3C, and MDN are nominative fair use. No affiliation is implied.