June 30, 2026
“Cross-Site Scripting in Practice: 5 PortSwigger Labs Broken Down”
Introduction
By Pranavaggarwal
5 min read
Introduction
XSS or what we call cross site scripting is a attacking technique which attackers use to inject malicious script in websites or pages used by users all over the globe.
Why XSS matters ?
XSS matters because of dangerous attacks like
- Cookie Theft — in this attack attacker steals the user cookie session with this he can impersonate into websites where user is logged in without knowing the password .
- Session Hijacking — in this attack the attacker hijack the active session between the user and the website
and many more attacks like keylogging ,phishing it's not just a simple popup.
In this post we will be understanding the 3 most important types of XSS .
- Reflected
- Stored
- DOM
Prerequisites / Setup
To follow along , You need a basic knowledge of how HTML is rendered in browser.
You'll also need Burp Suite (Community or Pro — both work fine for this) configured so that all your browser traffic passes through its proxy. This is non-negotiable; without it, you can't intercept or modify requests.
Knowing what DOM (document object model ) also helps in understanding .
Core Concepts
Why XSS attacks work ?
So , basically browsers trust HTML and JavaScript that comes directly from server so if a attacker injects its own script in between pages the browser execute it without any question , if its malicious it could cause severe damage .
Types of XSS
- Reflected —Payload (script here) travels in request usually URL and server reflect it back as a responses and browser executes it . it could affect only the person who clicked the link .
- Stored — payload gets saved to the database ( comments ,usernames ,posts) and then it affects to all the users who use that page .
- DOM — payload never touches the server it is done in javascript rendered in browser itself using a source (where the payload is injected ) and sink ( where the payload gets executed)
Key characters and why they matter:
<script>— classic injection tag<img onerror=>— bypass when script tags are filtered- "> — breaks out of HTML attribute context
location.search— DOM source that feeds untrusted input into the page
Labs Breakdown
Here are the 5 labs which help in understand what XSS is from scratch.
Lab1: Reflected XSS into HTML context with nothing encoded
Difficulty : Apprentice
Objective : Execute alert() via reflect XSS vulnerability in the search field
Vulnerability: Reflected XSS — no input sanitization, no encoding
My approach :
- What i noticed : the search box is appeared as soon as the page loads and the lab description also said that you have to execute alert using search field .
- Tested with a simple payload:
<script>alert(1)</script><script>alert(1)</script>- The website reflected it back and browser executed it
- since there is no filters , no encoding lab is solved using simple payload .
Key Insight: This is the baseline case . The server took my payload reflected it and browser executed it understanding why this works is most important (browser trust model) is more important than payload itself.
Lab 2: Stored XSS into HTML context with nothing encoded
Difficulty : Apprentice
objective : inject a script that executes when any user views the page .
Vulnerability : Stored XSS — input saved to database, served to all users.
My approach :
- found a comment /input field that stores data to the input .
- tried the same payload again .
<script>alert(1)</script><script>alert(1)</script>- returned to the home page the script executed .
- lab solved , now every user who visits that page script will execute.
Key Insight: Whenever we want to impact the website in a way that every user faces the issue we need to find a entry point which stores it data in server without encoding here comment is the entry point . we just saved the script the stored XSS sitting there waiting for users to load the page and script got executed.
Lab 3: DOM XSS in document.write sink using source location.search
Difficulty : Apprentice
Objective: Exploit a DOM-based XSS vulnerability where JavaScript writes unsanitized input into the page.
Vulnerability: DOM XSS — document.write sink, location.search source.
My approach :
- Noticed the search term appeared on the page — but this time checked the source carefully .
- The server response didn't contain my input — a JavaScript function was reading
location.searchand passing it todocument.write() - That means the payload needs to work inside whatever HTML context
document.writeis generating - Injected:
html
"><svg onload=alert(1)>"><svg onload=alert(1)>- The "> broke out of the existing HTML attribute, and
onloadtriggered the alert
Key Insight: This is where DOM XSS fundamentally differs. The server never saw my payload — the vulnerability exists entirely in the client-side JavaScript. Tools that only scan server responses would miss this completely, which is exactly why DOM XSS is harder to detect.
Lab 4: DOM XSS in innerHTML sink using source location.search
Difficulty: Apprentice
Objective : Exploit XSS via innerHTML — which behaves differently from document.write.
vulnerability : DOM XSS — innerHTML sink, location.search source.
My approach :
- This lab is similar to previous lab but there is only one difference the source is same but the sink is different
innerHTMLin this sink the script tag does not execute . - Tried the previous payload but it didn't fire
- Switched to an event-Handler payload insted
<img src=x onerror=alert(1)><img src=x onerror=alert(1)>- The browser tried to load an image which does not exist firing onerror attribute .
Key Insight: Not all sinks behave the same way. innerHTML blocks <script> execution but still processes event handlers on HTML elements. This is exactly why attackers use <img onerror=>, <svg onload=>, and similar alternatives when <script> is blocked — the attack surface is wider than just one tag.
Lab 5: Reflected XSS into attribute with angle brackets HTML-encoded
Difficulty: Apprentice
Objective: Execute XSS when the app HTML-encodes angle brackets — meaning < and > are neutralized.
Vulnerability: Reflected XSS — attribute context injection, angle brackets encoded
Lab 5: Reflected XSS into attribute with angle brackets HTML-encoded
Difficulty: Apprentice
Objective: Execute XSS when the app HTML-encodes angle brackets — meaning < and > are neutralized.
Vulnerability: Reflected XSS — attribute context injection, angle brackets encoded
My Approach:
- Tested
<script>alert(1)</script>— angle brackets were encoded, payload neutralized - Checked where my input was reflected — it was inside an HTML attribute value, not in the raw HTML body
- Since I'm already inside an attribute, I don't need angle brackets to break out — I just need to close the attribute and inject an event handler:
html
" autofocus onfocus=alert(1) x="" autofocus onfocus=alert(1) x="- This closes the existing attribute with ", adds
autofocusso the element gets focus immediately, firesonfocus=alert(1), thenx="cleans up the remaining quote
Key Insight: Context is everything in XSS. The payload that works in an HTML body context is completely different from the one that works inside an attribute. This lab teaches you to stop throwing <script> at everything and start thinking about where in the HTML your input is landing first.
Tools Used
- Burp Suite (Community/Pro) — primarily the Proxy and Repeater tabs
- PortSwigger Web Security Academy — lab environment
- Browser DevTools — essential for Labs 3 and 4 to inspect JS source
What I'm Tackling Next
with these 5 labs done i am moving on to the authentication i am doing apprentice labs of all the core topics once so that i can build a base and after that i will be moving on to more advanced version of these labs .
Links
- SQLi post Link
- For more projects GitHub
- LinkedIn : Pranav Aggarwal | LinkedIn