Samy Ghannad

Element.innerHTML and XSS Payloads

A while ago I was doing a security review of a web application, I came across a piece of JavaScript code which was obviously vulnerable, I could trigger the vulnerability with a typical <img> payload, but not with the classic <script> type. That made me dig dipper.

The vulnerable JavaScript code I was talking was something like this (changed a bit for easier reading):

1
2
3
4
5
6
var currentSearch = document.location.search;
var searchParams = new URLSearchParams(currentSearch);
var lang = searchParams.get('lang');
if (lang != null) {
 document.getElementById('ls').innerHTML = lang;
}

Lots of bad practices here, anyway, the lang parameter is vulnerable, it’s left here completely defenseless and naked,
So I tested it using a classic payload: <script>alert(1)</script> and it didn’t work! but why?!
I changed the payload to <img src=x onerror=alert(1)> and it triggered the XSS vulnerability.
Looking at the code I figured it out there must be something about either how this code reads and stores values OR the way it outputs the previously read values. Or both.
The first theory was rejected in 3 seconds, if there was a problem, an obstacle or protection, in the read & store part, things like encoding & filtering, it should have also affected the second payload, after all both of these payloads have some characters in common: <, > & alert(1), near zero possibility (although not 0, I would have came back to check this further haven’t I found the issue).
Then it should be the output part.
As a typical me would do, I jumped into the documentation of innerHTML and there it was!\

HTML5 specifies that a <script> tag inserted with innerHTML should not execute.

- Mozilla

A few lines below, it also states:

However, there are ways to execute JavaScript without using <script> elements, so there is still a security risk whenever you use innerHTML to set strings over which you have no control.

- Mozilla

It also uses <img src='x' onerror='alert(1)'> as an example of this how restriction can be bypassed.
Amazing!

\