What is MIME sniffing?

When the browser reads the first few bytes and decides it knows better than your header.

By Ihor Havrysh ยท Last reviewed July 2026

Eaglepedia mascot

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.

A response declared as plain text, rendered as markup without nosniff and served as text with it
The header settles what the browser does with your declaration. It does nothing about whether the declaration was right.

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.

Frequently asked questions

Compatibility. A great many servers have historically sent wrong or missing Content-Type headers, and a browser that obeyed them strictly would display broken pages where a competitor displayed working ones. Sniffing was the pragmatic answer: look at the first few hundred bytes, work out what the content really appears to be, and render that. The behaviour is now specified in the WHATWG MIME Sniffing standard so that browsers at least guess consistently.

When your application serves a file that a user supplied. You may declare it as plain text, but if the bytes look like HTML a sniffing browser may decide to render it as HTML, which means any script inside it runs in the context of the origin that served it. You made a safe declaration and the browser overrode it.

Send the response header X-Content-Type-Options with the value nosniff. That tells the browser to honour your declared Content-Type rather than inspecting the body. It is a single header, it is widely supported, and applying it to every response is the usual recommendation rather than only to uploads.

No. The header stops the browser overriding your declaration, so it only helps if your declaration is right. If your application stores whatever content type the client supplied and then echoes it back on download, you have simply moved the attacker's control from the sniffing algorithm to your own database. Derive the content type from your own validation, not from the upload.

A Content-Disposition header set to attachment, where users only need to retrieve files rather than view them, so the browser downloads instead of rendering. Serving user content from a separate origin, so anything that does execute has no access to your application's sessions. And a restrictive content security policy on that origin as a further backstop.
Ihor Havrysh - Software Engineer at Red Eagle Tech

About the author

Ihor Havrysh

Software Engineer

Software Engineer at Red Eagle Tech with expertise in cybersecurity, Power BI, and modern software architecture. I specialise in building secure, scalable solutions and helping businesses navigate complex technical challenges with practical, actionable insights.

Read more about Ihor

Discovery call

A friendly 15-minute video call with Kat to understand your needs. No preparation needed.

  • Discuss your project
  • Get honest advice
  • No obligation
Kat Korson, Founder of Red Eagle Tech

Kat Korson

Founder & Technical Director

Our team has 10+ years delivering software solutions for growing businesses across the UK.

Send us a message

Your information is secure. See our privacy policy.

Find us