What is Detectify?

Chrome XSS Protection Bias (using Rails)

January 15, 2014

The Chrome XSS Protection (also known as XSS auditor) checks whether a script that’s about to run on a web page is also present in the request that fetched that web page. If the script is present in the request, that’s a strong indication that the web server might have been tricked into reflecting the script. So in short, it blocks reflected XSS attacks. A couple of months ago I discovered that the Chrome XSS Protection could be bypassed in Rails. Later, when I saw the issue brought up on twitter by homakov, I figured I’d write something about it as well.

What is the Chrome XSS protection?

The Chrome XSS Protection (also known as XSS auditor) checks whether a script that’s about to run on a web page is also present in the request that fetched that web page. If the script is present in the request, that’s a strong indication that the web server might have been tricked into reflecting the script. So in short, it blocks reflected XSS attacks.

A couple of months ago I discovered that the Chrome XSS Protection could be bypassed in Rails. Later, when I saw the issue brought up on twitter by homakov, I figured I’d write something about it as well. Here’s how the testing went down:

First try

First off we started with creating a dummyscript with a straight forward XSS scenario. Here’s the code:

<h1>Variable: <%= raw params[:variable] %></h1>

Let’s test it with a basic cross-site scripting payload:

GET /?variable=<script>alert(1)</script> HTTP/1.1
<h1>Variable: <script>alert(1)</script></h1>

rails_xss_blocked

Oh, no! The XSS auditor blocked the attempt. Let’s try something a bit different!

The bypass

GET /?variable[<script>]=*alert(1)</script> HTTP/1.1
<h1>Variable: {"<script>"=>"*alert(1)</script>"}</h1>

rails_xss_bypass

It works! But why? Let’s have a closer look at the source code strip away everything except the <script> tag:

<script>"=>" * alert(1)</script>

Okay, so a bit more clear. The asterix will work as a multiplication of whatever’s on either side. So, the javascript will try to multiplicate the string “=>” with whatever the function alert() produces. Since alert doesn’t return anything, the righthand value will be “undefined” and the final result of the calculation will be “NaN”.

The XSS auditor probably misses this because Rails doesn’t print exactly what the browser sent, making it hard to filter automatically. However, Internet Explorers XSS auditor as well as NoScript finds it.

TL;DR: Chrome’s XSS auditor can be bypassed with rails like so: ?variable[<script>]=*alert(1)</script>.

Want to try the world’s (if you want to) cheapest web security scanner? Sign up here.


Author: Mathias Karlsson