Cross-Site Scripting (XSS) allows attackers to inject malicious scripts into web pages viewed by other users.
TL;DR
Cross-Site Scripting (XSS) is a client-side injection vulnerability (CWE-79, OWASP A03:2021) where an attacker injects malicious JavaScript into a web page served to other users. The injected code executes in the victim's browser under the origin of the vulnerable site, inheriting all its privileges: cookies, localStorage tokens, DOM access, and the ability to make authenticated requests on the victim's behalf.
XSS is the most prevalent client-side vulnerability class on the web. CWE-79 ranked #1 in both the 2024 and 2025 CWE Top 25, and approximately 20% of all valid HackerOne reports are XSS findings. The severity range is wide: a reflected XSS on a search box is CVSS 6.1, while a stored XSS firing in an administrator's dashboard can reach CVSS 9.3 Critical.
What makes XSS uniquely dangerous is the combination of ubiquity and impact scope. Session hijacking, credential harvesting, malware delivery, DOM manipulation, and CSRF amplification are all achievable through a single XSS vulnerability.
| Variant | Persistence | Attack Target | Detection | Typical CVSS |
|---|---|---|---|---|
| Reflected | None — lives in URL | Victim browser | Server-side scanner | 6.1 |
| Stored | Database / files | All visitors | Write + readback canary | 7.2–9.3 |
| DOM-based | None — client-side | Victim browser | Headless browser taint | 6.1–8.8 |
| Blind | Backend / logs | Admin panels | OOB callback token | 8.5–9.1 |
| Mutation (mXSS) | Varies | Sanitizer consumers | Differential parsing | 6.1–9.0 |
All XSS variants share the same fundamental flow: attacker-controlled data reaches a browser rendering context without correct sanitization or encoding.
Once executing in the victim's browser, an XSS payload can:
document.cookie (non-HttpOnly) and send it to the attackerlocalStorage.getItem('access_token') and exfiltrate itfetch() from admin browser to internal APIs (combined Blind XSS + SSRF)unsafe-inline in script-src, defeating all nonce/hash protections (HTTP Archive / Flatt Security Research 2024)Referer, User-Agent), JSON fields rendered in HTML, file metadataxsstest"'<> and inspect the raw response bodyBreachVex detects XSS across all five variant classes using a two-pass approach: canary reflection with context classification followed by context-appropriate payload injection, with real-browser execution confirmation and out-of-band token callbacks.
Encode at the exact injection context. Context determines the encoding scheme:
from markupsafe import escape
import json
from urllib.parse import quote
# HTML body / attribute context
safe_html = escape(user_input) # & " ' < > → HTML entities
# JavaScript string context (inside <script> tags)
safe_js = json.dumps(user_input) # wraps in quotes, escapes all specials
# URL context
safe_url = quote(user_input, safe='') # percent-encode every special charA strict nonce-based CSP breaks most XSS exploits even when encoding is bypassed:
Content-Security-Policy:
default-src 'none';
script-src 'nonce-RANDOM_PER_REQUEST' 'strict-dynamic';
object-src 'none';
base-uri 'none';
require-trusted-types-for 'script';'unsafe-inline' completely defeats nonce and hash protections. Any CSP containing it provides no meaningful XSS mitigation. 91% of deployed CSP headers contain this directive.
Trusted Types (enforced on YouTube, Microsoft 365, and Stripe as of 2024) requires all DOM sink assignments to go through a developer-defined policy:
const policy = trustedTypes.createPolicy('default', {
createHTML: (input) => DOMPurify.sanitize(input),
});
element.innerHTML = policy.createHTML(userInput); // safe — goes through sanitizer
element.innerHTML = userInput; // throws TypeError in enforced modeEnable via CSP: require-trusted-types-for 'script'
Set-Cookie: session=abc123; HttpOnly; Secure; SameSite=StrictHttpOnly prevents document.cookie theft. SameSite=Strict prevents CSRF chains from XSS payloads. Neither prevents XSS itself — they reduce the impact of a successful exploitation.
XSS is a client-side injection vulnerability where an attacker injects malicious JavaScript into a web page served to other users. The script executes in the victim's browser under the targeted site's origin, inheriting its cookies, tokens, and DOM access.
The five major variants are: Reflected XSS (non-persistent, requires victim to click a link), Stored XSS (persisted in the database, fires for every visitor), DOM-based XSS (client-side only, server response is clean), Blind XSS (stored variant that fires in admin panels the attacker cannot see), and Mutation XSS (bypasses sanitizers via browser HTML re-parsing).
Stored XSS targeting admin panels reaches CVSS 9.3 (Critical) because it fires automatically for every authenticated administrator without requiring any interaction beyond page load. Blind XSS shares this severity for the same reason.
Reflected and DOM-based XSS baseline at CVSS 6.1 (CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N). Stored XSS targeting privileged users reaches 9.3 (Scope: Changed, Confidentiality: High, Integrity: High).
The injected script reads document.cookie and sends it to an attacker-controlled server via fetch() or an img src trick. HttpOnly cookies are invisible to JavaScript, but XSS can still make authenticated requests on behalf of the victim and exfiltrate localStorage tokens.
Output encoding prevents XSS when applied at the correct context (HTML body, HTML attribute, JavaScript string, URL, CSS each require different encoding). Missing the context or encoding at input time instead of output time leaves gaps. CSP and Trusted Types add independent defense layers.
XSS accounts for approximately 20% of all valid HackerOne vulnerability reports, making it the single most reported vulnerability class on the platform.
Yes. 91% of desktop sites with CSP still include unsafe-inline in script-src, defeating all nonce and hash protections. Even strict CSPs can be bypassed via JSONP endpoints, DOM clobbering, or prototype pollution gadgets.