Reading Time: 6 minutes

XSS Case Study

Gergő Turcsányi (Content Development Expert, Avatao)

You’ve probably heard about the recent Cross-Site Scripting vulnerability in the Google search engine. With a clever payload, you could have crafted a link that executes JavaScript after opening it and clicking into the input box.

The bug was found by Masato Kinugawa and LiveOverflow has made a video about it which went viral! (it really is worth it to check it out, plus you can find a lot of additional great stuff on his YouTube channel as well). The video clearly explains the bug, but practice makes perfect so we’ve created a tutorial challenge about the bug, where you can:

  • Exploit the same vulnerability
  • Play with the HTML parser of your browser
  • See how the vulnerable version of the sanitizer worked

Also, we think it’s worth highlighting the key elements and main points of the story, which is also the goal of this post

    Dealing with user input

    Simply encoding special characters could have prevented the issue, but… in some cases, you want to allow some HTML tags, for example when writing emails (formatting text, inserting links and images). It means you have to actually parse the code and remove its unwanted parts, like JavaScript and exotic attributes.

      Then let’s sanitize it on the client-side

      It sounds really wrong – so why would Google do that? Because parsing HTML isn’t as easy as you may think. The specification is really complex and the implementation can be different in the browsers as well. Additionally, browsers don’t just simply parse the HTML – they’re fixing malformed code, completing missing tags, paying attention to headers, loading external resources. Implementing and maintaining a library for that would be really hard – especially because of the different versions of the different browsers. I guess using the client for that makes more sense now.

        But how to do it securely?

        There’s a very special <template> tag which is perfect for the job. Its content is parsed, but not rendered. That means the browser does its magic (like fixing the missing closing tags), but it won’t execute scripts or load images. The basic concept of sanitizing HTML on the client is the following:

        • Loading the user input into a <template> tag and letting the browser parse it
        • Removing scripts and unwanted tags and attributes (by using a whitelist for example)
        • The result can now be used securely in the HTML code

          The issue

          And here comes the <noscript> tag which is really special as well. The specification says:

          The noscript element represents nothing if scripting is enabled, and represents its children if scripting is disabled. It’s used to present different markup to user agents that support scripting and those that don’t support scripting, by affecting how the document is parsed.

          Inside the <template> element scripting is disabled, but in the browser (after using the sanitized HTML in the DOM) scripting is enabled. Combining this fact with the helpful behavior of the browsers (where they finish incomplete tags) led to the ultimate payload, which could’ve been used to bypass the Google – Closure and the Cure53 – DOMPurify libraries (both are popular HTML sanitizers):

          <noscript><p title='</noscript><img src=x onerror=alert(1)>'>
          

          It’s parsed inside the template element like this:

          scripts disabled

          But when it’s used in scripting enabled context it becomes:

          scripts enabled

          And boom – the alert(1) is executed. It’s a really awesome example of how weird browsers can be and motivation for all the bug bounty hunters out there. I bet almost none of us thought that we’d see a working XSS on the homepage of Google.

          How could it have been avoided?

          The funny thing is that they (at Google) knew about this attack vector already and fixed the code a long time ago. However they didn’t add any unit tests and when someone later reverted it, the build passed (because it didn’t break the non-existent test) and the vulnerability ended up in the production code. So I think the most important takeaway from the story is tests are really important.

            Why?

            I’ve seen the video multiple times, checked many-many comments about this vulnerability, and played with the JS debugger for hours, but none of these could answer why was the user input parsed as HTML in the search engine?, which is the real question here I think. But even if it wasn’t the case – the payload probably could’ve worked in Gmail.

              Let’s play

              On our platform you can find several exercises related to Cross-Site Scripting. Why don’t you try one?

              security bugs ebook

              Related Articles

              Why is Cloud Data Privacy Important?

              Why is Cloud Data Privacy Important?

              Reading Time: 9 minutes The cloud data system has numerous advantages as well as many dangers. 80% of companies have had at least one data breach in the past months.

              Why you need SOC2 compliance as a third party vendor

              Why you need SOC2 compliance as a third party vendor

              Reading Time: 7 minutes Companies understand the way you handle data security has a direct impact on their bottom lines. This has led to most companies requiring all vendors to have a special compliance certificate called an SOC2.

              Hacktivity 2021 – Our experiences

              Hacktivity 2021 – Our experiences

              Reading Time: 7 minutes Our team attended Hacktivity, the biggest IT security conference in Central and Eastern Europe – a whole day full of interesting presentations and workshops. Click to see how we liked it!