🔒
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 ↗