ThreatFoundacademy
Web Application Security
Web Application Security

Cross-Site Scripting (XSS)

How attacker-controlled input becomes executable JavaScript in a victim’s browser — and how to prove it.

10 min read

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 from localStorage.
  • 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.