← Back to the Build Your Homepage series
🔒
EPISODE 01
Stored · reflected · DOM · escaping · CSP

XSS — Cross-Site Scripting

XSS lets attackers inject scripts that run in your users' browsers. Learn the three flavors, how to escape output, and how Content Security Policy gives defense in depth.

XSSsecurityCSPescaping
Duration
About 1.5 hours
Level
📊 Intermediate
Prerequisite
🎯 JavaScript track
OUTCOME
Render any user content safely; ship a basic CSP

What you'll learn

  • 1Distinguish stored, reflected, and DOM XSS
  • 2Always escape output (default in React/Vue/Angular)
  • 3Avoid innerHTML / dangerouslySetInnerHTML
  • 4Configure a Content Security Policy

1. The Three Flavors

  • Stored — payload saved on the server (e.g., in a comment) and served to other users
  • Reflected — payload in a URL/query that the server reflects back into HTML
  • DOM — JavaScript on the client builds HTML from untrusted input

2. Always Escape Output

javascript
// VULNERABLE
el.innerHTML = `<p>Hello, ${userInput}</p>`;
// If userInput = '<img src=x onerror="alert(1)">' — game over

// SAFE
el.textContent = `Hello, ${userInput}`;
// Or React: {userInput} is auto-escaped
⚠️

Avoid React's dangerouslySetInnerHTML unless you sanitize input with a library like DOMPurify first.

3. Sanitize When You Must Render HTML

javascript
import DOMPurify from "dompurify";
const clean = DOMPurify.sanitize(richHtml);
el.innerHTML = clean;

4. Content Security Policy (CSP)

text
Content-Security-Policy: default-src 'self'; script-src 'self' https://cdn.example.com; img-src 'self' data: https:

Even if an attacker injects a <script>, the browser refuses to run it unless it matches your CSP. Defense in depth.

Example code / lecture materials

All lecture materials and example code are openly available on GitHub.

View on GitHub ↗