Goodbye XSS Auditor

Chrome’s development team has decided to retire the XSS Auditor, its inbuilt Cross-Site-Scripting (XSS) filter that aimed to prevent reflected Cross Site Scripting vulnerabilities in the majority of cases. While this move might surprise many observers, it follows a long list of bypasses, security related side effects and false positives that revealed serious problems with the XSS Auditor. Let’s examine a little of the XSS Auditor’s history, how it worked and why it was retired. We’ll also examine what you, as a developer, can do to stay secure in the event of an undetected XSS vulnerability on your website.

Goodbye XSS Auditor

How Did the XSS Auditor Work?

The way in which the XSS Auditor worked was quite simple. Whenever you sent a request to a web server, Google Chrome would take a look at the URL bar, as well as the POST body, if applicable. It would search for dangerous strings that could lead to the execution of JavaScript code, such as certain HTML tags, event handlers, external URLs, and URI schemes such as data or JavaScript. However, it wouldn’t block these requests right away. Instead, it would wait for a response from the server to check whether these dangerous inputs were actually reflected on the page without any sanitization. Only in that case would the XSS Auditor take action, either by preventing the whole page from loading or by removing the injected script.

Bypassing the XSS Auditor

The XSS Auditor wasn’t perfect. Over the years, many bypasses were reported to the Chrome development team. Some were clever and required an in-depth understanding of HTML, JavaScript, the XSS Auditor and Chrome’s rendering engine. Others were confusing or downright ridiculous. But regardless of the cause of the issues, once they were reported, they were fixed. But this didn’t prevent hackers, developers and researchers from finding additional issues.

In addition, there were some conceptual problems that couldn’t be fixed in the XSS Auditor’s code. For example, consider what would happen if a developer decided to remove all single quotes from the input in an attempt to prevent SQL Injections. The XSS Auditor would see <'s'c'r'i'p't'> in the input, but the server would send back <script> in the output. How could Chrome be sure that this was caused by the input containing the single quotes? There was the same issue with removing words such as SELECT from the input, which you could abuse with <scSELECTript>. The XSS Auditor was able to detect similar mutations to a certain extent, but you couldn’t reasonably expect it to catch every possible change on the server side, at least not without a large quantity of false positives.

But if most of the obvious problems were fixed once the developers knew about them, wouldn’t that mean that users were generally safe from XSS, if they weren’t facing dedicated attackers with in-depth knowledge of Cross-Site-Scripting and the XSS Auditor? While it certainly became harder over the years to find a proper bypass for the XSS Auditor, it wasn’t impossible, and many were published. Such bypasses were expected from the beginning. 

The Auditor’s Troubled Beginnings

In January 2010, on the same day the changelog for version 4.0.249.78 (which introduced the XSS Auditor) was uploaded, the Chrome development team published a blog post called Security in Depth: New Security Features, explaining the new security features of the release. Here is a quote from the post:

We are aware of a few ways to bypass the filter, but, on balance, we think that the filter is providing enough benefit to enable it by default in this release. If you discover a new way to bypass the filter, please let us know. We’re very interested in improving the filter in subsequent releases. We’re grateful to the security researchers who have helped us with the filter thus far (especially Eduardo “Sirdarckcat” Vela), and we welcome even more participation.

It’s telling that one of the next changelogs on the Chrome blog mentioned that the XSS Auditor was disabled again. However, this was apparently due to performance issues in certain cases. After that, it was hidden behind a Chrome flag and only enabled by default again some time later.

The XSS Auditor Was Not a Panacea 

Another issue was the sheer amount of Google Chrome users. When you design software for a specific purpose, you can have a very clear understanding of what your users want to achieve with it. For example, if you want to develop an app for an important government institution, you would have to implement every conceivable security measure, from mandatory 2FA to certificate pinning. But if you want to develop a simple weather app without login functionality, such security measures would be disproportionate. Chrome has, by far, the largest share in the browser market. Creating a uniform threat model for its one billion plus users is not possible. There are too many different use cases and too many users.

So the decision to implement a security measure that only deters less dedicated attackers, leaving high-value targets at risk, wasn’t ideal, even though it helped protect many users from the dangers of XSS. Fortunately, a superior anti-XSS measure was invented – the Content Security Policy (CSP). It is more effective, less prone to bypasses – if implemented correctly – and most importantly, it allows websites to define their own threat model and apply restrictions accordingly. While it doesn’t protect users if websites don’t implement it, the removal of the XSS Auditor gives businesses the incentive to fix XSS vulnerabilities or implement CSP in order to stay secure. 

Vulnerabilities Caused By the XSS Auditor

The XSS Auditor led to serious security concerns. At first, it removed dangerous scripts by default. But this was considered insecure because security features could be deactivated that way. Then, the XSS Auditor started to block entire pages in its default setting. But this was considered insecure because it led to information leaks. Finally, it reverted to removing dangerous scripts. While this was still insecure, it was judged to be less problematic than allowing information leaks. Netsparker published XSS Auditors – Abuses, Updates and Protection following the XSS Auditor’s last update, showing how it had reverted all default behaviour to a previously used version on this basis.

Disabling Scripts With the XSS Auditor

Instead of preventing the whole page from rendering, the XSS Auditor removed the dangerous script and rendered the rest of it. This was highly problematic. The reason is that the Auditor couldn’t detect which script was put on the page by the developer and which one was put there by an attacker. All it could do was compare the request and response.

Imagine there is a script like this on the page:

<script>callSecurityRelatedFunction()</script>

This function could contain a frame buster – a piece of code that tries to determine whether the page was loaded in an iframe, which would somehow prevent the page from rendering – a concept similar to the X-Frame-Options HTTP header. If an attacker wanted to remove this functionality they could append the script to the query string.

/account?attacker=<script>callSecurityRelatedFunction()</script>

The XSS Auditor would see the script in the request and think that an attacker put it there. It would then remove the script from the page, which effectively disables the security measure that the developer wanted to implement.

Serious Information Leaks

That Google went back on its original tactic of blocking the entire page and instead defaulted to this obviously problematic setting probably meant there was a more severe issue with blocking the complete page. The culprit was likely an information leak vulnerability that could be abused under certain circumstances. There may be multiple possible issues, but generally this is how such an information leak may work.

A developer places a script like this on their website:

<script>const userSecret = 23456</script>

The website contains other scripts, images, videos, fonts, and external styles. They all take a measurable amount of time to load. After they are finished loading, for example in an iframe, an attacker might receive a notification, through something like an onload event handle. What they can do now is send different payloads.

/account?attacker=<script>const userSecret = 1 // takes some time to load
/account?attacker=<script>const userSecret = 2 // instantly failes due to being blocked by the auditor
/account?attacker=<script>const userSecret = 21 // takes some time to load
/account?attacker=<script>const userSecret = 22 // takes some time to load
/account?attacker=<script>const userSecret = 23 // fails as it's being blocked

This is a simple example. The reality might be a little more complex than this, but these are the basics of how such an information leak vulnerability would work. It is the same concept as a blind SQL Injection, but applied to JavaScript, the XSS Auditor and the Same Origin Policy.

A Secure Alternative for the XSS Auditor

All of these problems, and others we don’t have space to mention, eventually led to the retirement of the XSS Auditor. Many will miss it, but the Content Security Policy header is a worthy successor. In terms of information security, it’s often the case that the easy plug and play (PnP) solutions like the XSS Auditor provide less protection than a CSP. A CSP must be correctly configured and implemented but it does allow you to define clear and concise limitations.

Implementing a CSP is not easy and we highly recommend that you read the Netsparker blog post Content Security Policy (CSP) Explained as well as the relevant section of our whitepaper HTTP Security Headers and How They Work. You should scan your website with an application security scanner like Netsparker, which will detect the Negative Impact of Incorrect CSP Implementations, such as the unsafe-inline keyword, missing quotes or the usage of invalid CSP directives in meta tags. With a correctly implemented CSP on your website, it’ll be much easier saying goodbye to the XSS Auditor.


*** This is a Security Bloggers Network syndicated blog from Netsparker, Web Application Security Scanner authored by Sven Morgenroth. Read the original post at: https://www.netsparker.com/blog/web-security/goodbye-xss-auditor/