The two primary methods of avoiding Cross-site Scripting (XSS) vulnerabilities are XSS filtering and XSS escaping. However, XSS filtering is not recommended because it can usually be evaded using clever tricks. Here are some of the methods that an attacker can employ in their malicious code to easily bypass the XSS filters in your web application.
Why Is XSS Filtering So Difficult?
XSS filters work by finding typical patterns that may be used as XSS attack vectors and removing such code fragments from user input data. Patterns are most often found using regular expressions. This is very difficult for two primary reasons:
- Patterns that may signify an XSS payload may also be used legitimately, as a content of the web page (for example, in this article). Therefore, the filter must be able to avoid false positives.
In theory, it is possible to create a nearly foolproof XSS filter. However, the complexity of this filter would be enormous and there is always a chance that someone will come up with a new bypassing technique. That is why escaping is the easier and the recommended method of preventing XSS attacks.
Cross-site Scripting Filter Bypass Cheat Sheet
The following are the most common methods used by attackers to fool XSS filters. Of course, all these methods may be combined or refined. You can find more examples in the OWASP resource based on the XSS Cheat Sheet by RSnake.
Using Character Encoding
The simplest XSS vector used to defeat filters is based on encoding characters that may trigger a filter. You may use different techniques for encoding, for example, base64, HTML entities, or others. The encoding will depend on what exactly needs to be encoded, for example,
href tag URLs support URL encoding but tag names do not. All the other methods described below are often used with some form of encoding.
For example, to fool filters that look for typical ASCII patterns, you may replace
script:alert(document.cookie). Note that you may also skip any or all semicolons.
If the filter knows how to recognize encoding attempts, you may try to trick it by using decimal encoding with padding and by skipping semicolons. For example,
alert is equivalent to
Case Manipulation and Character Insertion
If the filter is case-sensitive, it may be fooled if you use a different case than the one that is expected. For example, you may use
<Script> or even
Additionally, modern web browsers usually ignore extra spaces, tabs, newlines, and carriage returns that you insert in the HTML tag. For example, you can use
<script[\x13]>. You can also attempt to insert a null byte anywhere, for example,
Fooling Regular Expressions
Sometimes bypassing a filter requires no more than finding a method to fool the regex. For example, you can use fake tags with brackets:
<script a=">" src="http://example.com/xss.jpg"></script>. If the regexp is not written correctly, it will assume that the script tag ends with the first closing bracket. Also, note how the file is named to mimic a JPG image and fool filters that look for specific file extensions.
Using Atypical Event Handlers
onload, there are a lot of other event handlers that you can try to use, for example marquee-related event handlers such as
onfinish, and many more. The most comprehensive list of such handlers is available on W3Schools.
Tricks with Tags and Attributes
Some filters focus only on the common tags. Therefore, you can use uncommon tags to bypass them, such as
<svg>. However, filters often forget to include such obvious tags as
Using Atypical Delimiters
There are several characters that may be used as delimiters instead of whitespaces – modern browsers will still execute the code properly. For example, you may use double quotes, single quotes, and even backticks (only for some browsers). For example,
You may also try to use extra angle brackets and slashes (comments) to trick filters, for example
<<script>alert(document.cookie)//<</script>. Modern browsers are often so tolerant that they may even execute the following code properly:
<iframe src=http://xss.example.com/xss.html <.
Also, note that the first whitespace after the tag name may be replaced by even more delimiters. For example, you may replace it by a single slash:
Making Other Deliberate Mistakes
While deliberate mistakes can help you bypass many filters, browsers will still understand the context. This is especially true when you use quotes in the wrong place, in the wrong order, or forget to close quotes.
A very simple example of this is:
<input type="text" name="test" value="><script>alert("xss")</script>. The unclosed quote after
value may fool the filter but the code will still be executed because most browsers will treat the quote as closed and fix the code internally.
Another deliberate mistake used to fool filters is adding junk content after the tag name. Many modern browsers will completely ignore such added content, so, for example, you can use
<script/anything> instead of
<script> (note the use of the single slash delimiter described in the previous section).
The Past, the Present, and the Future
Filter evasion keeps evolving and you can expect new methods to appear in the future as they are being discovered. Many methods can also be used together to make evasion more effective, for example, you can use
meta tags such as
refresh along with base64 encoding
Note that some XSS filter evasion cheat sheets currently available online have not been updated for many years and many techniques listed there no longer work. Here are some of the most interesting techniques that are included in such cheat sheets but work only in very old browsers (in some cases, even as old as Netscape):
imgtags such as
- Using CSS:
fromCharCodeto escape disallowed content, for example,
- Using VBScript in an image:
<img src='vbscript:msgbox("warning")'>or using livescript
Get the latest content on web security
in your inbox each week.