Content Security Policy (CSP)
debt(d3/e5/b5/t7)
Closest to 'default linter catches the common case' (d3). The term's detection_hints.tools list includes lighthouse, owasp-zap, and csp-evaluator — these are mainstream security/quality scanners that will flag missing CSP headers or dangerous directives like unsafe-inline. Not quite d1 since it's not a compile-time error, but readily caught by common web security tooling.
Closest to 'touches multiple files / significant refactor in one component' (e5). The quick_fix suggests starting with a restrictive policy and adding nonces for inline scripts. While setting the header itself is one line, actually implementing nonces across all inline scripts requires touching every template/view that has inline JS, and potentially refactoring JavaScript to external files. For legacy applications with scattered inline scripts, this is a significant refactor.
Closest to 'persistent productivity tax' (b5). CSP applies to all web contexts and becomes a persistent consideration — every new script source, inline handler, or third-party integration must be evaluated against the policy. Developers must remember to add nonces, update the policy for new CDNs, and maintain awareness of what sources are allowed. It's not quite b7 (doesn't shape every change), but it's a tax on frontend work indefinitely.
Closest to 'serious trap' (t7). The misconception field explicitly states that developers believe 'unsafe-inline still meaningfully prevents XSS' when in fact it defeats the primary purpose of CSP entirely. This is a serious trap because the policy appears to be working (header is set, no errors), but provides essentially no XSS protection. Developers familiar with other security headers may assume presence equals protection, contradicting how CSP actually requires strict configuration to be effective.
Also Known As
TL;DR
Explanation
CSP is a defence-in-depth measure against XSS. By declaring a policy via the Content-Security-Policy header, you tell the browser to refuse executing inline scripts, loading scripts from untrusted domains, or evaluating eval(). Even if an attacker injects a script tag, CSP prevents it from running. A strict CSP (script-src 'nonce-{random}') is the most effective configuration. CSP does not replace output encoding — it is an additional layer.
Diagram
flowchart TD
PAGE[Page served with CSP header] --> BROWSER3[Browser enforces policy]
BROWSER3 --> SCRIPTS{Script source allowed?}
SCRIPTS -->|from own domain| ALLOW3[Execute]
SCRIPTS -->|inline script tag| BLOCK3[Block - no unsafe-inline]
SCRIPTS -->|from cdn example.com| CHECK3{In script-src?}
CHECK3 -->|yes| ALLOW3
CHECK3 -->|no| BLOCK3
subgraph Directives
DEFAULT[default-src self]
SCRIPT[script-src self nonce-xyz]
STYLE[style-src self unsafe-inline]
IMG[img-src self data blob]
end
style ALLOW3 fill:#238636,color:#fff
style BLOCK3 fill:#f85149,color:#fff
Common Misconception
Why It Matters
Common Mistakes
- Using unsafe-inline in the script-src directive — negates XSS protection entirely.
- Using unsafe-eval — allows string-to-code execution which attackers can exploit.
- An overly permissive default-src: * that effectively disables source restrictions.
- Not deploying CSP at all, relying solely on output encoding which may have gaps.
Avoid When
- Setting unsafe-inline or unsafe-eval — these negate the XSS protection that CSP exists to provide.
- Deploying CSP in enforce mode before testing in report-only mode — you will break legitimate functionality.
- Using wildcard (*) sources for script-src — a wildcard allows loading scripts from any origin.
- Setting CSP only on the HTML page but not on API responses that return HTML fragments.
When To Use
- Any web application that renders user-supplied content — CSP is the last line of defence against XSS.
- Applications with a well-defined set of trusted script, style, and media sources.
- After completing XSS remediation — CSP reduces the blast radius of any XSS that slips through.
- Report-only mode first, to identify violations before enforcing.
Code Examples
// Overly permissive CSP that provides no XSS protection:
header("Content-Security-Policy: default-src *; script-src * 'unsafe-inline' 'unsafe-eval'");
// Tight CSP — no inline scripts, only own domain + CDN
header("Content-Security-Policy: " .
"default-src 'self'; " .
"script-src 'self' https://cdn.jsdelivr.net; " .
"style-src 'self' 'unsafe-inline'; " .
"img-src 'self' data: https:; " .
"font-src 'self'; " .
"connect-src 'self' https://api.yourapp.com; " .
"frame-ancestors 'none'; " .
"base-uri 'self'; " .
"form-action 'self';"
);
// Start in report-only mode to detect breakage before enforcing:
header('Content-Security-Policy-Report-Only: ...; report-uri /csp-report');