TL;DR: Cross-site scripting is attacker-controlled content executing as script in your origin, with the victim's session: stored (saved and served to others), reflected (echoed from a request) or DOM-based (client code moving data into a dangerous sink). Prevent it by encoding at output for the exact context (HTML text, attribute, URL, JavaScript), which frameworks do by default unless bypassed; by sanitising with an allowlist when HTML must be rendered; and by a strict, nonce-based CSP that blocks injected scripts as a second layer.
How to approach it
Define XSS by its impact, give the three kinds, then explain why encoding happens at output and depends on context. Close with CSP's role and its limits.
A strong answer
- 1
1 · Contextual encoding
At output, per context
- HTML body, attribute, URL, JavaScript each differ
- Framework auto-escaping by default
- 2
2 · Safe sinks
Avoid raw HTML APIs
- textContent over innerHTML; sanitise rich text
- 3
3 · Strict CSP
Nonce or hash based
- Blocks injected inline script
- 4
4 · Cookie hardening
Limit what script can steal
- HttpOnly; script can still act as the user
Impact. Script in your page can do anything the user can: call APIs with their cookies, read the page, change what they see, capture input. HttpOnly cookies prevent reading the session cookie, not acting as the user.
Encode at output, by context. The same data needs different treatment depending on where it lands:
| Context | Danger | Encoding |
|---|---|---|
| HTML body | <script>, event-handler attributes | HTML-entity encode |
| Quoted attribute | Breaking out with a quote | Attribute-encode; always quote |
URL in href/src | javascript: URLs | Validate scheme (http, https, mailto); percent-encode parameters |
Inside <script> | Breaking out of strings or the tag | Avoid; pass data as JSON in a data attribute |
Encoding at input is the wrong place: input may end up in several contexts, and encoding for one breaks another. Frameworks such as React escape interpolated values automatically; the bugs live in bypasses like dangerouslySetInnerHTML, v-html, innerHTML and template |safe filters.
Sanitise when rendering HTML is the feature. Rich text and Markdown produce HTML deliberately. Use a vetted sanitiser such as DOMPurify with a strict allowlist of tags and attributes, disable raw HTML in Markdown renderers, and restrict link schemes.
CSP as defence in depth. A policy like script-src 'nonce-<random>' 'strict-dynamic'; object-src 'none'; base-uri 'none' means injected inline scripts and event handlers do not run, because they lack the nonce. Add img-src restrictions to stop data exfiltration through images. CSP does not fix the bug; it makes many bugs unexploitable. For DOM XSS, Trusted Types enforce safe values at dangerous sinks.
AI chat interfaces. Model output is attacker-influenced whenever the model reads attacker content, so the renderer must treat it like user input: safe Markdown, sanitised HTML, restricted links and images, and stored conversations treated as stored content.
What interviewers probe next
- "Does CSP stop DOM XSS?" Partly: it blocks injected script execution if
unsafe-inlineandunsafe-evalare absent, but not all DOM manipulation; Trusted Types cover the sinks. - "Is HttpOnly enough?" No; script can still make requests as the user while the page is open.
- "How do you find XSS in a large React app?" Search for raw-HTML sinks and URL attributes built from data, and test with a browser-based scanner.
What if?
What if · interview follow-ups
Hold your answer as the constraints change
A product review page displays the reviewer's name and comment, both written by users, and some reviews are shown in an admin dashboard too.
Start here
What forms does cross-site scripting take?
Where does the attacker's content come from in each case?
Attacker-controlled content executing as script in your origin with the victim's session: stored (saved and served to others), reflected (echoed from a request) or DOM-based (client code moving data into a dangerous sink).
Carry it forwardStored, reflected and DOM-based XSS.
Weak answerThinking XSS needs a script tag in the URL.
Constraint changes
How do you prevent it?
What does the browser need to see to treat data as text?
Encode at output for the exact context (HTML text, attribute, URL, JavaScript), which frameworks do by default unless bypassed. Input validation helps, but output encoding is the control.
Carry it forwardContext-aware output encoding.
Weak answerFiltering input for angle brackets.
Constraint changes
What if reviews must allow some formatting?
Which tags and attributes are safe?
Sanitise with an allowlist of safe tags and attributes using a maintained sanitiser, and render the result into an HTML context only. Never write your own HTML filter.
Carry it forwardAllowlist sanitisation for rich text.
Weak answerBlocklisting dangerous tags.
Constraint changes
Why is the admin dashboard a special risk?
Whose session runs the script in the dashboard?
Stored XSS shown to admins runs with admin sessions, so an attacker can act as an administrator. Admin views of user content need the same encoding, and often stricter defaults.
Carry it forwardStored XSS in admin views escalates privileges.
Weak answerRelaxing encoding in internal tools.
Constraint changes
What adds defence in depth?
What helps if one template is wrong?
A strict nonce- or hash-based Content Security Policy, HttpOnly session cookies and Trusted Types for DOM sinks. They limit damage if encoding is bypassed somewhere, but they do not replace encoding.
Carry it forwardCSP and Trusted Types back up encoding.
Weak answerRelying on CSP alone.
Now defend it
How would you secure the review page?
Rely on framework auto-escaping with context-aware encoding and avoid bypasses; sanitise any rich text with a maintained allowlist sanitiser; apply the same rules in admin views; add a strict nonce-based CSP, Trusted Types and HttpOnly cookies; and test with benign markers in reviews.
How it's scored
Weak: Says "sanitise user input" and stops, or confuses XSS with CSRF.
Hire: Explains the three kinds, contextual output encoding, and framework escaping and its bypasses.
Strong Hire: Covers URL schemes, sanitisation for rich content, a concrete strict CSP, Trusted Types, and model output in chat UIs.
Common mistakes
- HTML-encoding at input and storing encoded data.
- Allowing
javascript:links from user or model content. - Using
unsafe-inlinein CSP, which defeats its purpose. - Rendering model Markdown with raw HTML enabled.