What is XSS and how do you prevent it?
Take a moment.
Say your answer out loud or write it down first — retrieval is what makes it stick. Reveal when you're ready.
Short answer
XSS injects attacker JavaScript into your pages: stored (saved in your DB, served to everyone), reflected (bounced off a URL param), or DOM-based (client-side code writing attacker data into the page). Prevent by escaping output in the right context, avoiding dangerous sinks (innerHTML, eval), and layering a Content Security Policy plus HttpOnly cookies.
Detailed explanation
XSS runs with your origin's full privileges: reading tokens from storage, acting as the user, defacing content. Stored XSS is the worst — a comment containing <script> saved once executes for every future visitor. Reflected XSS hides in links (search?q=<script>…) and fires for whoever clicks. DOM-based XSS never touches the server: client code like element.innerHTML = location.hash writes attacker input straight into the DOM. Prevention is layered. First, framework defaults: React/Vue/Angular escape interpolations automatically — the bugs appear where you bypass them (dangerouslySetInnerHTML, v-html) or concatenate HTML strings. Second, context-aware output encoding: HTML-escape text nodes, attribute-escape attribute values, and never place untrusted data in script contexts or javascript: URLs. Third, kill the dangerous sinks: prefer textContent over innerHTML, JSON.parse over eval, and sanitize any rich HTML with a allowlist sanitizer (DOMPurify) on input. Fourth, blast-radius reduction: Content-Security-Policy headers (script-src 'self', no inline scripts) make injected scripts refuse to execute even if one slips through; HttpOnly cookies keep session ids out of document.cookie; and Trusted Types (modern Chrome) can enforce that only sanitized values reach sinks. Validate on input for business rules, encode on output for safety — the two are different jobs.
Example
// ❌ DOM-based XSS: hash content becomes live markup
// el.innerHTML = location.hash.slice(1);
// ✅ text stays text
el.textContent = location.hash.slice(1);
// Rich text you must keep? Sanitize with an allowlist:
// import DOMPurify from 'dompurify';
// el.innerHTML = DOMPurify.sanitize(userHtml);
// Defense in depth via headers (server or CDN):
// Content-Security-Policy: default-src 'self'; script-src 'self'; object-src 'none'
// Set-Cookie: sessionId=…; HttpOnly; Secure; SameSite=LaxInterview tip
Name all three types with a one-line example each, then give the layered defense (encode → avoid sinks → CSP → HttpOnly). Saying 'validate on input, encode on output' closes it cleanly.
Common mistakes
- Believing HTTPS or input validation alone stops XSS.
- Using innerHTML/v-html with unsanitized data.
- Skipping CSP because 'we escape everything' — one miss is total compromise.