‘nosniff’ and the rabbit hole of MIME sniffing in browsers

apoorv munshi
4 min readJun 18, 2018

--

One frequent finding in web application security assessments is that the application has not deployed the X-Content-Type-Options (XCTO) response header . If you look at the Open Web Application Security Project (OWASP) website for information about this header, it will tell you that the header is used to prevent browsers from sniffing the response and interpreting it as a different MIME type than the one declared in Content-Type response header. However, I wanted to find a more convincing argument about the exploitability of this vulnerability, which is usually rated as “low risk” in security assessments. That lead me to discover many interesting things about MIME sniffing in browsers. So, let’s see what risks are posed to applications if they don’t use this header.

During the initial Googling around phase, I started with the Mozilla Developer Network article which led me to the fetch specification page of XCTO. The parsing algorithm mentioned in section 3.3.1 of the specification can be summarized as follows:

  • Check if XCTO header is present in response with the value “nosniff”
  • If the destination of request is “script-like” or “style” and the Content-Type header value in response is not a valid JavaScript or CSS MIME type respectively, block the response from being rendered.

Why only Script and Style (CSS) destinations? Its because only these contexts are “executable” and could be potentially harmful for an application. JavaScript (JS) is obviously executable context but JS is also permitted in CSS stylesheets in some cases.

Now, the word destination in the algorithm means parsing context .Consider the src attribute of a <script> tag. Whatever source you will specify for the script tag, the browser may try to interpret it as JavaScript (JS). This is where MIME sniffing comes into play. If the Content-Type response header is a valid JS MIME type, the browser will attempt to parse it. However, even if the Content-Type header value is not valid for script context, the browser may still try to parse it as JS. Here, the behavior of each browser may vary due to differences in MIME sniffing algorithms.

To see MIME sniffing in action, please open these links in Chrome and Edge and observe the source code as well as messages in browser console :

http://www.debugtheweb.com/test/mime/script.asp (work of @ ericlaw)

http://w3c-test.org/fetch/nosniff/importscripts.html

Notice that Chrome (tested in 67.0.3396.87 on Win10) parses Javascript even if the Content-Type is text/plain.

Now to the real question. In what scenarios can an attacker exploit a resource for which the XCTO options header is not present ? In my opinion, the following preconditions exist for an exploitation opportunity :

  1. There should be some application resource, the content of which is controlled by the attacker.
  2. The attacker can introduce an executable context in the application (For example, a<script> tag or a <link> tag).

Then, the application resource in control of the attacker can be specified as a source for the executable context.

The application’s resource could become “executable” if:

  • application sets a wrong Content-Type response header for the attacker controlled content

OR

  • the Content-Type IS appropriate for the response BUT the MIME sniffing algorithm of the browser sniffs the response and determines to parse it for the context

Thus, attacks such as cross-site scripting (XSS) are possible due to missing XCTO options header. However, it's not convincing enough, right ? If there is a cross-site scripting bug, the attacker can include remote script for exploitation. Absence of XCTO header is not necessarily needed. When I was thinking about this issue, I thought about Content Security Policy (CSP)bypass possibility . Also, around same time, I read about a new protection mechanism called as Cross-Origin Read Blocking (CORB) , which was enabled in Chrome 67. So, let’s talk about these two cases.

Possibility to bypass Content Security Policy (CSP):

Let's assume that an application has a CSP which prevents loading of scripts from any other origins except the application’s own origin. Also, the application has a file upload functionality allowing upload of text files on the hosting origin. When sending the uploaded text file in response, the application sets Content-Type as text/plain but without XCTO header. An attacker who can upload files to the application can place malicious JavaScript in a text file and then give it as a source to a script tag to exploit a XSS vulnerability. As per current MIME sniffing behaviour of Chrome, it will be successfully parsed, causing a CSP bypass.

Using XCTO to enable CORB protections

When studying this issue, I decided to look at Google.com to see for what type of responses they were setting the XCTO header. At first, I was confused to see that it was set for text/html responses too. However, when I read the detailed CORB explainer, I understood why. It turns out that XCTO can also enable CORB defenses against Cross-Site Script Inclusion (XSSI) and side-channel attacks on browser’s renderer processes (ex. spectre). Please read the CORB explainer for more details. It gets more interesting !

While studying this , I understood how vast and complex the topic of MIME sniffing is and hence the title.

What developers should do ?

Developers should ensure that the Content-Type header in all response has appropriate value for the response. Also, the X-Content-Type-Options header value should be set to nosniff for at least following types of responses:

  • HTML
  • CSS
  • JSON
  • XML
  • JavaScript
  • Text

Special thanks to Devdatta Akhawe for proofreading this article.

References :

--

--