Understanding MIME types and content sniffing
29 December, 2025
Any web or web-adjacent developer worth their salt has probably come across the Content-Type HTTP header at some point. I have always held an ambiguous notion that this header contains “a MIME type”, which the browser will somehow interpret to decide what to do with the data.
Recently I had to deal with a bug caused by this mundane header, and was forced to actually read up on MIME types, how browsers deal with them, and how to correctly use them.
History of the MIME types
MIME (Multipurpose Internet Mail Extensions) types originated in the early 90s as a way to let emails carry data other than ASCII text, such as images, attachments and different character sets.
As HTTP came around, it reused these types in the form of the Content-Type header. I was just a baby back then, but from what I’ve read, this system did not work very well in the early days of the web: servers regularly answered with types that were either wrong or completely made up, forcing browsers to fall back on sniffing and other heuristics to figure out what to do with the response data.
Over time this guesswork grew to be quite a burden, but more importantly it became a security risk. MIME confusion attacks for example could be used to trick browsers to run JavaScript disguised as JSON, parse HTML disguised as an image, or accomplish cross-site scripting with mislabeled content.
As time went on the web matured, standards tightened, and browsers became stricter. MIME types transformed from “possibly helpful hints” to actual contracts, and non-standard types that once may have worked by accident now fail by design.
What is a MIME type?
Before diving into how browsers deal with MIME types, it’s worth briefly looking at what a MIME type actually is.
I won’t rewrite the official spec here, but in a nutshell a MIME type is a label that describes the data format with a type and a subtype. For example text/html, image/webp, or application/json.
The “top-level” type before the forward slash indicates the broader category (text, image, application, etc.), and the subtype specifies exact format.
List of official MIME types is maintained by IANA, but many legacy and vendor-specific types still exist.
How browsers deal with MIME types
As stated above, MIME types tell the clients how to interpret the response data: maybe it’s an image or HTML that should be rendered inline, or maybe it’s JavaScript that should be executed.
Content-Type header is consulted first and used as the primary signal. Since only a limited set of MIME types map to renderable or executable content, unknown or unsupported types are handled cautiously, which usually means they will be treated as files and written to disk.
Content sniffing
Content sniffing is a fallback mechanism that browsers use when dealing with incorrect or missing MIME types. It acts as a tightly constrained compatibility layer that applies to a narrow set of legacy formats, follows standardized rules, and is often disabled entirely via security headers like X-Content-Type-Options: nosniff.
The mechanism itself is simple: instead of trusting the Content-Type explicitly, inspects the first few “magic bytes” of the response, and compare them to a tiny hardcoded set of known signatures to see what to do with the data.
The bug
Let’s circle back to the bug that prompted the need to learn about MIME types.
In this case, certain (completely valid) ICO files were uploaded and subsequently served by the application with an incorrect MIME type of image/ico. This type is still widely used throughout the internet, and browsers are perfectly capable of sniffing out the magic bytes 00 00 01 00 to identify the data.
The root cause – perhaps unsuprisingly – was that content sniffing had been disabled with the aforementioned nosniff content type option, removing the escape hatch. Browsers were forced to take the MIME type at face value, and since it did not map to an officially sanctioned one, fall back to downloading the file instead of rendering it as a site icon.
The fix was trivial to implement once understood: serve the file with the official MIME type of image/vnd.microsoft.icon
The name is weird, but apparently Microsoft originally came up with the ICO format so they got to name the corresponding MIME type.
Final thoughts
This “bug” was ultimately just the intended behaviour of MIME types. Disabling content sniffing removes an entire class of MIME related attack vectors, but in the process of doing so also exposes any existing misconfigurations and latent bugs realting to content types.
I think the broader lesson is that today, MIME types are not just cosmetic metadata or mere suggestions. In modern, security-conscious systems they are a binding contract between the server and the client. Relying on content sniffing may work today and exist of out of necessity, but it’s fundamentally brittle and hopefully on its way out completely.