How to stop cross site scripting (XSS)?
xss-no-csp-protection global
The issue
Cross-site scripting lets someone else’s code run inside your page, with the visitor’s session. It can read what the page shows, capture what the visitor types and act as them. A single output-encoding mistake anywhere on the site is enough, and without a Content Security Policy nothing limits what the injected code can do.
The cause is a policy that is missing, or one that still allows the routes injected code uses: inline scripts, eval(), and scripts from any origin.
Scope
The policy applies to the whole document that receives it. It is normally set once for the site, so a weak policy weakens every page.
How to check you have it
- In probeo: the related findings are
csp-missingwhen there is no policy, andcsp:script-src-unsafe-inline,csp:script-src-unsafe-eval,csp:script-src-wildcardandcsp:script-src-data, each graded major, when the policy allows inline scripts,eval(), any origin ordata:scripts. - By hand: run
curl -sI https://your-site.example/ | grep -i content-security-policyand readscript-src, ordefault-srcif it is absent. Look for'unsafe-inline','unsafe-eval',*,https:anddata:. - With a tool: Google’s CSP Evaluator reports each of these.
The fix
Enforce a script-src that allows only named sources, with no 'unsafe-inline' and no 'unsafe-eval'.
Move inline scripts into files, or give each one a nonce or hash. Replace inline event handlers with addEventListener, and remove eval() and new Function(). Keep output encoding as it is; the policy is the second layer, not a replacement.
Done when: the enforced policy allows scripts only from named sources or by nonce or hash, and the check above comes back clean.
Do not
- Do not keep
'unsafe-inline'or'unsafe-eval'in a production policy. - Do not add
data:orblob:toscript-src. - Do not drop output encoding because a policy exists.
- Do not allow every origin with a wildcard.
FAQ
Does CSP eliminate the need for output encoding?
No. Encoding stops injected content from becoming code. The policy stops it from running if encoding fails somewhere. Both are needed.
What breaks when unsafe-inline is removed?
Inline <script> blocks without a nonce or hash, and inline event handlers such as onclick. Inline styles are governed separately, by style-src.
Can CSP be deployed gradually?
Yes. Send the policy as Content-Security-Policy-Report-Only first, fix what the reports show, then enforce it.
How do nonces work for inline scripts?
The server generates a random value for each response and puts it in the policy and in the nonce attribute of each script it trusts. The browser runs only inline scripts whose nonce matches. An injected script can’t know the value.
Does CSP protect against all XSS types?
No. It blocks injected scripts from running, which covers much of reflected and stored XSS. DOM-based XSS through APIs such as innerHTML needs safe code as well; the Trusted Types directives are the policy-side control for that.
What happens when third-party scripts are necessary?
List their origins in script-src. A listed origin can run any code on the page, so keep the list short. For scripts that don’t change, Subresource Integrity checks each file against a known hash.
Which product detects this
Probeo checks this on every page of your site as part of Site Clarity. This page explains one instance; the product tells you every page that has it.