Update/TL;DR: If you didn’t generate it, assume it’s malicious.
Sometimes, the state of your website’s security can be affected by resources and services outside your control. The topic of today? Browser extensions.
Recently, we disclosed a vulnerability to a well-known company (let’s refer to them as Company) in their browser extension (specifically, in Chrome). To their credit, Company responded rapidly and fixed the issue within 2 days – major props to them for responding so quickly. Before we get into the vulnerability, let’s talk a little about what the extension does.
The vulnerability boils down to the following: if a page had a hashtag in its content that, as part of the hashtag, had an HTML-escaped element appended, it would get unescaped and then, by definition, inserted directly into the DOM by Company’s browser extension. Consider the following example:
If this showed up in the text of a page, the extension noticed the #tinfoil hashtag and attempted to convert it into a link. So the above became something like the following:
You’ll notice that this is malformed HTML to begin with (the #tinfoil attribute of the a tag, for example), but the more important issue is that the Company’s browser extension actually unescapes the escaped HTML for the script tag and, in doing so, inserts it into the DOM. Of course, the link still works, pulling up a search for #tinfoil as it should, so if we weren’t popping up an alert box, the user would be none the wiser.
User generated content occurs everywhere, and it is always important to escape any input you may receive. The mantra we often use is: “If you didn’t generate it, assume it’s malicious.” In this case, the document returned by the website the user is visiting should be considered potentially malicious. The extension is acting on data it did not create, and as such should treat it more carefully than it would other data, by escaping everything it can. So if you’re building a browser extension, be sure to treat the DOM of whatever page you’re modifying as dangerous, because it is.