Cross-Site Scripting (XSS)
How attacker-controlled input becomes executable JavaScript in a victim’s browser — and how to prove it.
XSS happens when an application takes input from one user and reflects it into a page without proper encoding, so the browser parses it as code instead of data. The attacker’s JavaScript then runs in the victim’s session.
The three flavours
- Reflected — the payload is in the request (e.g. a URL parameter) and echoed straight back in the response. Needs the victim to open a crafted link.
- Stored — the payload is saved (a comment, a profile name) and served to everyone who views it. The most dangerous.
- DOM-based — the sink is client-side JavaScript (e.g.
innerHTML = location.hash); the server may never see the payload.
A minimal proof
Suppose a search page renders your query into the HTML body:
GET /search?q=<svg/onload=alert(document.domain)>
…<h2>Results for <svg/onload=alert(document.domain)></h2>…If the <svg> executes, you have reflected XSS. Use document.domain rather than alert(1) in a real report — it proves *which origin* you’re executing in, which matters for impact.
Showing a payload reflected in the response is NOT proof on its own. You must show it actually executes (an alert, a Burp Collaborator callback) and account for Content-Type and CSP — otherwise it’s “unconfirmed reflection”, not XSS.
Why it’s serious
- Steal session cookies (if not
HttpOnly) or auth tokens fromlocalStorage. - Perform actions as the victim — change email, add an SSH key, transfer funds.
- Keylog, phish in-page, or pivot to internal apps the victim can reach.
The fix
Context-aware output encoding (HTML, attribute, JS, URL contexts each differ), a strict Content-Security-Policy as defence-in-depth, and framework auto-escaping. Never build HTML by string concatenation with user input.