What is XSS (Cross-Site Scripting)?
Definition
XSS (Cross-Site Scripting) is a vulnerability in which a web application places untrusted data into a page without proper encoding, allowing attacker-controlled script to run in other users' browsers with the site's own privileges. The three main types are stored, reflected and DOM-based XSS. The core defence is context-aware output encoding, while Content Security Policy and HttpOnly cookies limit the damage.
Also known as: Cross-Site Scripting, stored XSS, reflected XSS, DOM-based XSS, script injection

Script running as the site
What makes XSS so damaging is that the injected script runs in the target site's own origin, not on the attacker's domain. To the browser it has the same rights as the site's legitimate code: it can read anything on the page, send requests with the user's session, overlay a fake login form and access tokens in localStorage or cookies not marked HttpOnly. It also defeats CSRF tokens, because the script can simply read the token from the page.
Stored, reflected and DOM-based
| Type | Where the data comes from | Typical location |
|---|---|---|
| Stored | Content saved in the database and shown to later visitors | Comments, display names, support tickets, product reviews |
| Reflected | A request parameter written back into the same response | Search results pages, error messages; the victim has to open a crafted link |
| DOM-based | Client-side JavaScript taking data from the URL, postMessage or similar and writing it into a dangerous API | Single-page applications; the server may never see the data |
All three share one root mistake: data ends up somewhere it is interpreted as markup or code instead of as text. Understanding how the browser represents the page as a DOM tree makes the DOM-based variant much easier to reason about.
A vulnerable pattern and its fix
// Vulnerable: the user-supplied value is parsed as HTML
resultsHeading.innerHTML = "Results for: " + searchTerm;
// Safe: the value is inserted as plain text
resultsHeading.textContent = "Results for: " + searchTerm;With the second line, whatever the search term contains is shown literally. The same principle applies on the server: use a template engine with auto-escaping and reach for its escape hatches, such as React's dangerouslySetInnerHTML or Vue's v-html, only when there is no alternative. Where users genuinely need to submit HTML, as in a rich text editor, pass the output through a well-maintained sanitiser with a strict allowlist of tags and attributes.
Encoding depends on context. Data written into an HTML body, an attribute value, a JavaScript string or a URL each needs different rules. For links built from user input, also check that the URL uses an expected scheme such as https:.
Layers of defence
- Context-aware output encoding: the actual fix; everything else reduces impact.
- Input validation: enforcing expected formats helps but is not sufficient on its own.
- Content Security Policy: a strict nonce-based policy stops most injected scripts from executing when an encoding bug slips through.
- HttpOnly cookies: keep the session cookie out of reach of script, though they cannot stop script from acting as the user.
OWASP's XSS prevention cheat sheet stresses that no single technique solves XSS.
Finding XSS before someone else does
Code review focuses on dangerous sinks: innerHTML, outerHTML, document.write, eval, framework components that render raw HTML and event-handler attributes fed with user data. Static analysis tools flag many of these patterns automatically. A CSP in report-only mode surfaces unexpected inline scripts in production. For critical applications, regular penetration tests catch the contexts automated tools miss.

