MIME sniffing is when a browser inspects the beginning of a response body and decides the content type for itself rather than trusting the Content-Type header the server sent. It exists to cope with misconfigured servers, and it can cause an uploaded file to be treated as something more dangerous than intended.
Why browsers guess
In principle a server states what it is sending and the browser believes it. In practice a very large number of servers have always sent the wrong content type, or none at all, and a browser that obeyed those headers strictly would render broken pages where a more forgiving competitor rendered working ones.
So browsers learned to look. They read the opening bytes of a response, compare them against known patterns, and decide what the content actually appears to be. If a response claims to be plain text but begins with markup, a sniffing browser may conclude it is really HTML and render it accordingly.
This started as competing, undocumented guesswork, which produced the worst of both worlds: unpredictable behaviour that differed between browsers and that attackers understood better than developers did. The WHATWG MIME Sniffing standard exists to make the algorithm consistent and documented, so that at least the guessing is the same everywhere.
Why it matters for uploads
Sniffing is largely harmless when a server is serving its own content, because the person who wrote the file and the person who configured the header are on the same side.
It stops being harmless the moment your application serves a file that somebody else supplied. Now the content of the response is chosen by a user, and the browser is deciding how to treat it based on that content rather than on your declaration.
The pattern is straightforward. Your application accepts an upload, stores it, and serves it back with a deliberately conservative content type. A sniffing browser reads the bytes, sees something that looks like markup, and renders it as a document. Anything scriptable inside it now runs in the context of whichever origin served it, which is usually yours.
You did the right thing at the header and were overruled by the client. That is what makes this worth understanding: it is a case where correct server-side behaviour is not, by itself, sufficient.
It compounds with the other content-type problems. The Content-Type on the way in is supplied by the client and proves nothing, which is why checking magic bytes rather than trusting the declared type matters. Sniffing is the same class of problem pointed in the opposite direction, on the way back out.
Switching it off, and what else to do
The direct control is one response header:
X-Content-Type-Options: nosniff
It tells the browser to honour the Content-Type you declared rather than inspecting the body to second-guess it. Support is universal in current browsers, and the usual recommendation is to apply it to every response your application produces rather than only to file downloads, since there is very little reason to want sniffing anywhere.
One important caveat: nosniff only helps if your declared type is right. If your application records whatever content type the client sent at upload time and replays it on download, you have moved the attacker's influence from the browser's sniffing algorithm into your own database, and the header will faithfully enforce their choice. Derive the content type from your own validation of the file, and store that.
Three controls pair naturally with it:
- Content-Disposition: attachment where users only need to retrieve a file rather than view it in place, so the browser downloads instead of rendering
- A separate origin for user content, so that anything which does execute has no access to sessions or storage belonging to your application
- A restrictive content security policy on that origin, as a backstop for whatever gets through the first two
These matter most for formats that are documents in disguise. An SVG is XML that a browser will happily parse as a document, and HTML masquerading as a text file is the textbook sniffing case. Rebuilding uploaded files, rather than storing them as received, removes the ambiguity before any of this arises.
Our guide to file upload security covers how the inbound and outbound halves of this fit together across a whole upload pipeline.
Headers control how a file is treated. Reconstruction controls what it is. The Red Eagle Tech CDR API rebuilds documents from their safe components before you store them, so the file you serve later is one you assembled rather than one you received. Published per-document pricing and self-service signup.