Explain stored, reflected, and DOM-based XSS.
Short answer
All XSS injects attacker-controlled script into a victim's browser. Stored XSS persists the payload on the server (e.g. a comment) and hits everyone who views it; reflected XSS bounces the payload off the server in a single response, usually via a crafted link; DOM-based XSS never reaches the server logic — vulnerable client-side JavaScript writes untrusted input into the page.
Cross-site scripting (XSS) is the class of bugs where an attacker gets their JavaScript to run in another user's browser session, inside the trusted origin of your site. Once that happens, the script can read cookies, the DOM, and tokens, make authenticated requests, and impersonate the victim. The three flavors differ in where the payload lives and how it reaches execution — and that difference drives both detection and the fix.
Stored (persistent)
The payload is saved on the server — in a database, a comment field, a profile name — and served back to every user who loads that content. This is the most dangerous form because it needs no per-victim interaction and can spread like a worm. One injected <script> in a forum post can hit thousands of sessions.
Reflected (non-persistent)
The payload is included in a request (a query parameter, form field) and immediately reflected back in the response without being stored. The attacker must lure each victim into clicking a crafted link or submitting a malicious form. It is single-shot per victim, but devastating in phishing.
DOM-based
Here the server may be entirely innocent. Vulnerable client-side JavaScript reads attacker-controllable input (like location.hash) and writes it into a dangerous sink such as innerHTML, document.write, or eval. The payload may never appear in any HTTP request body the server processes, which is why server-side WAFs and logs can miss it. The injected script itself is drawn from the same families of XSS payloads regardless of how it reaches the sink.
Why the distinction matters
Stored and reflected are mitigated largely by contextual output encoding on the server and a strong Content-Security-Policy. DOM XSS must be fixed in the client code — using safe APIs like textContent and setAttribute instead of innerHTML.
Interviewers look for the where/how framing, naming a concrete sink for DOM XSS, and an awareness that stored XSS is usually the highest priority because of its blast radius.
Likely follow-ups
- Why is DOM-based XSS sometimes invisible to a server-side WAF?
- Which sinks (innerHTML, document.write) make DOM XSS possible?
- How would you prioritize fixing stored vs reflected XSS?