Lesson 8 / 25
Cross-Site Scripting (XSS)
Encode output, use safe APIs, add CSP.
Untrusted data in a page
XSS lets attackers run JavaScript in other users' browsers by injecting it into pages: stored (saved in a comment), reflected (in a URL parameter) or DOM-based (client code writes untrusted data into the page). Defences: rely on frameworks that auto-escape output (React, Angular, Django templates), avoid raw HTML sinks (innerHTML, dangerouslySetInnerHTML, v-html) or sanitise with a vetted library such as DOMPurify, encode for the right context (HTML, attribute, URL, JavaScript), and add a Content Security Policy as a second layer.
Unsafe and safe DOM updates plus a CSP header
JavaScript and an HTTP header.
// VULNERABLE: interprets the comment as HTML, so <img src=x onerror=...> runs code
commentEl.innerHTML = comment.text;
// SAFE: treat it as text
commentEl.textContent = comment.text;
// If rich HTML is required, sanitise with a vetted library
commentEl.innerHTML = DOMPurify.sanitize(comment.html);
// HTTP response header limiting where scripts may come from
// Content-Security-Policy: default-src 'self'; script-src 'self'; object-src 'none'; base-uri 'self'Set HttpOnly on session cookies
HttpOnly prevents scripts from reading the session cookie, limiting what an XSS payload can steal.
Quick check: Which DOM property safely inserts untrusted text?
- outerHTML
- innerHTML
- textContent
- document.write
Answer
textContent — Text is never parsed as HTML.