MIME Sniffing Introduction
MIME stands for “Multipurpose Internet Mail Extensions.” MIME was originally defined to support non-ASCII text and non-text binaries in email. However, the content types defined in MIME standard are used in HTTP protocol to define the type of content in a request or response.
A browser usually identifies a resource’s MIME type by observing the Content-Type response header in an HTTP response.
“MIME sniffing” can be broadly defined as the practice adopted by browsers to determine the effective MIME type of a web resource by examining the content of the response instead of relying on the Content-Type header. MIME sniffing is performed only under specific conditions. Please note that MIME sniffing algorithms vary by browser. A MIME sniffing standard has been defined on the Web Hypertext Application Technology Working Group (WHATWG) website.
A demo of MIME sniffing behavior of browsers can be run from a simple Docker container that can be set up from the GitHub repository:
Follow the instructions in the GitHub README to download the container, build, and run it. Then open the web page in a browser of your choice where the traffic is run through a proxy such as OWASP ZAP, and observe the relevant HTTP response headers as well as the messages in the console.
X-Content-Type-Options HTTP Header
X-Content-Type-Options (XCTO) is a security-related HTTP response header used by servers to instruct browsers to not perform MIME sniffing. The only possible directive for this header is nosniff. This header should be deployed by developers when they are sure that the MIME type in Content-Type header is appropriate for the response’s content.
There are some additional advantages of using this header if the client is a Chromium based browser. We will see more details about this in a later section of this article.
Cross-Site Scripting Using MIME Sniffing
- <script> tags
- <link> tags
Now, let’s see how MIME sniffing can result in a XSS vulnerability. For an attacker to perform an XSS attack by leveraging MIME sniffing, there are certain preconditions.
Preconditions on client side (both necessary for successful exploitation):
- The attacker should be able to introduce an executable context via HTML injection
Preconditions on the server side (only one necessary for successful exploitation):
Once these preconditions are satisfied, attacker can use HTML injection to inject executable context and then specify the source as the attacker-controlled resource. An example exploit payload is as follows:
<script src=”https://example.com/attacker_controlled_resource” ></script>
What if CSP is Present?
Let’s assume that example.com deploys a Content Security Policy (CSP) that mitigates XSS exploits by disallowing scripts included from remote hosts. An example of such CSP would be:
Content-Security-Policy: default-src ‘self’; img-src https://example.com; script-src https://example.com
<script src=”https://example.com/attacker.txt” ></script>
In the above scenarios, if the developers deploy the XCTO header and specify the correct value of the Content-Type response header, XSS attack can be mitigated.
Other Uses of the XCTO Header
As mentioned earlier, XCTO header is useful in triggering mitigations against some other classes of vulnerabilities in Chromium based browsers. This defense mechanism is known as Cross Origin Read Blocking (CORB).
CORB protects against two types of attacks:
- Cross-Site Script Inclusion (XSSI)
- Speculative Side Channel Attacks such as Spectre (when Site Isolation is enabled)
However, CORB is currently available only for certain types of resources under certain conditions. The details about CORB are out of scope of this post. We will highly recommend you to read the CORB explainer document for more details.
What Should Developers Do?
Developers should always make sure that all resources served by a web application have correct Content-Type header value in response. Also, the X-Content-Type-Options header with nosniff directive should be deployed for all application responses.