Yes, DOM-based XSS is still a concern. While some issues cannot be exploited due to URL encoding, there a number of situations where URL encoding will not stand in the way of exploitation.
The gist of the example is to form a hashbang query with injection
That's one example, but DOM-based XSS encompasses all XSS issues that result from insecurely handling data via JavaScript.
Data can come from sources such as the URL, the DOM itself, etc.
The most basic example where user input is eg read from location.search
and processed with innerHTML
or .write
will indeed not work with any up-to-date browser, as the value is URL-encoded.
But DOM-based XSS with different sources than location.search
or different sinks than innerHTML
will still work, and do exist in real-world applications.
An incomplete list of examples with different sinks and sources can be found below.
Source: URL
An example for a DOM-based XSS vulnerability where the user input comes from the URL:
<html>
<body>
<script>
url = new URLSearchParams(location.search);
x = url.get('x');
document.write(x);
</script>
</body>
</html>
Attack:
http://example.com/test.html?x=<script>alert(1)</script>
Source: The DOM
In my experience, this is the most common class of exploitable DOM-based XSS issues.
Let's assume an application that properly HTML-encodes all user-supplied data that is inserted into the HTML code.
Applications will still often read out user-supplied data from the DOM, and then reinsert it in an insecure manner. For example:
<html>
<body>
<input type="text" id="userinput" value=""><img src=x onerror=alert(1)>">
<div id="output"></div>
<script>
userinput = document.getElementById('userinput').value;
output = document.getElementById('output');
output.innerHTML = "Your input was: " + userinput;
</script>
</body>
</html>
Sink: Eval
Sometimes, we don't need "
or >
to gain XSS. An example would be user input that is passed to eval
:
<html>
<body>
<script>
x = window.location.hash.substr(1);
eval("var myvar = '" + x + "'");
</script>
</body>
</html>
Attack:
http://example.com/test.html#';alert(1);x='
Sink: document.write
Another example where we do not need "
or >
and which works with document.write
:
<html>
<body>
<script>
x = window.location.hash.substr(1);
document.write("<input type='text' value='" + x + "'");
</script>
</body>
</html>
</body>
</html>
Attack:
http://example.com/test.html#test'onmouseover='alert(1)