How to stop cross site scripting (XSS)?
xss-no-csp-protectionglobal
Cross-site scripting occurs when untrusted content executes as code in the page context. Without restrictions, browsers execute any script element regardless of origin. Content Security Policy defines which sources can provide executable code. A strict CSP prevents injected scripts from running even when output encoding fails.
What’s wrong
The site lacks a Content Security Policy that restricts script execution sources. Browsers execute scripts from any origin by default. If user input reaches HTML output without proper encoding, the injected script runs with full page privileges. Inline event handlers and eval() provide additional execution paths. The page trusts all code equally.
Why it matters
XSS defeats same-origin policy by making malicious code appear to originate from the trusted site. Injected scripts access cookies, session tokens, and DOM content. They can modify the page, capture keystrokes, and exfiltrate data. A single encoding error anywhere in the application creates an exploit path. Defense requires eliminating execution paths, not perfecting every output.
The correct change
Implement a Content Security Policy that restricts script-src to trusted origins. Remove inline scripts and event handlers. Eliminate eval() and similar string-to-code functions. Use nonces or hashes for necessary inline code. The end state is a page where scripts can only load from explicitly allowed sources using controlled mechanisms. Injection cannot create execution regardless of encoding failures.
Scope
This condition applies globally. CSP is set via HTTP header or meta tag and affects the entire page. All scripts, stylesheets, and executable resources fall under policy control. Individual elements cannot override the policy to permit execution.
How to verify
- Validation confirms the condition is resolved:
- • Content-Security-Policy header present with script-src directive
- • Script sources limited to self or specific trusted origins
- • No unsafe-inline or unsafe-eval in script-src
- • Inline scripts use nonces or hashes if necessary
- • Inline event handlers removed from HTML
- • eval() and new Function() calls eliminated
- • Browser console shows CSP blocking violations during testing
- • Injected script tags fail to execute
Takeaway
- XSS succeeds when browsers cannot distinguish trusted code from injected code
- Content Security Policy creates explicit trust boundaries for code execution
- Strict CSP blocks XSS even when output encoding fails
- Inline scripts and eval() bypass CSP protections and must be removed
FAQ
Does CSP eliminate the need for output encoding?
No. Output encoding prevents injection. CSP prevents execution if injection occurs. Both layers are necessary. Encoding stops malicious content from entering the DOM. CSP stops it from executing if encoding fails. Defense in depth requires both controls.
What breaks when unsafe-inline is removed?
Inline event handlers like onclick stop working. Inline script tags without nonces fail to execute. Style attributes and style tags require style-src adjustments. Most modern frameworks avoid these patterns. Legacy code requires refactoring to external files or nonce implementation.
Can CSP be deployed gradually?
Yes. Start with Content-Security-Policy-Report-Only to log violations without enforcement. Review reports to identify code needing updates. Transition to enforcing mode once violations are resolved. Gradual rollout reduces deployment risk on complex sites.
How do nonces work for inline scripts?
Server generates a random nonce for each response. The nonce appears in both the CSP header and script tag nonce attributes. Browsers execute only scripts whose nonce matches the policy. Injected scripts cannot guess the nonce. Nonces change per response, preventing reuse.
Does CSP protect against all XSS types?
CSP protects against reflected and stored XSS by preventing script execution. DOM-based XSS can bypass CSP if code uses dangerous sinks like eval or innerHTML with attacker-controlled data. CSP combined with safe DOM manipulation practices provides comprehensive protection.
What happens when third-party scripts are necessary?
Add their origin to script-src. Each third-party origin must be explicitly listed. Be aware that listed origins can execute arbitrary code. Limit third-party scripts to essential services. Use Subresource Integrity (SRI) to ensure scripts match expected hashes.
The fix
Prevent cross-site scripting by restricting code execution to trusted sources
Done when: Content Security Policy enforces script-src restrictions, eliminating unsafe-inline and unsafe-eval, ensuring only explicitly trusted code can execute
Do not
- Do not include unsafe-inline or unsafe-eval in production policies
- Do not add data: or blob: to script-src without understanding the risks
- Do not assume CSP alone protects without output encoding
- Do not use overly permissive CSP that allows all origins via wildcards
How to verify
- Content-Security-Policy header present with script-src
- No unsafe-inline or unsafe-eval in script-src
- Inline scripts removed or use nonces/hashes
- Inline event handlers eliminated
- Test injections fail to execute
- Browser console shows CSP blocking violations
Find every page with this
probeo monitors this continuously across every page of your site, and records which pages passed, which failed, and which it could not determine.
Book a Call