What is MIME sniffing?
When a browser loads a file from the server, the server announces what it is via the
Content-Type header —
text/html,
image/png,
application/javascript
and so on. But what happens when the server doesn't send a Content-Type at all or sends
an obviously wrong one (e.g. a .gif file with
text/plain)?
Historically, this is where MIME sniffing came in: browsers peeked at the first few bytes of the file and tried to detect the type themselves. Looks like HTML? Then render it as HTML, no matter what the header says. That was pragmatic in the early web — many servers used to set Content-Types sloppily — but today it's a security hole.
The security problem
Imagine this: on your website, users can upload files — for example profile pictures.
The attacker uploads a file that looks like a valid PNG but contains HTML with
embedded JavaScript in its body. The server serves it with
image/png — so far, harmless.
A browser without sniffing would load the image, the script would never execute.
But: if the browser has sniffing enabled and discovers HTML markup in the body, it suddenly renders the file as HTML — the embedded JavaScript runs in the context of your domain and can access cookies, sessions and all data of logged-in users. A cozy file upload turns into a full-blown XSS attack.
The same problem exists in reverse: depending on browser sniffing logic, a harmless text file can suddenly be executed as a script, a PDF as HTML and so on. Another classic: old Adobe Flash-based sniffing bypasses.
The solution: nosniff
The header
X-Content-Type-Options: nosniff
tells the browser unambiguously:
"Trust the Content-Type header exclusively. Don't sniff. If I say something is
image/png, then load it as an
image — and nothing else."
With nosniff, the upload attack described above becomes ineffective: the browser sees
Content-Type: image/png and treats
the file strictly as an image. Even if HTML is embedded — no rendering, no script.
Prerequisite: the server sends a sensible Content-Type. With a missing header, nosniff
stays conservative and won't load the file as executable.
Values
The header only knows one meaningful value:
nosniff. Everything else is ignored.
X-Content-Type-Options: nosniff
Configuration examples
nginx:
add_header X-Content-Type-Options "nosniff" always;
Apache:
Header always set X-Content-Type-Options "nosniff"
Express:
app.use(helmet.noSniff())
Cloudflare: in the dashboard under Rules → Transform Rules → Modify Response Header.
Prerequisite: correct Content-Types
nosniff only works if your server actually delivers the correct Content-Types.
An image served as text/plain
won't load anymore — nosniff blocks it. Poorly configured servers may suddenly run into
functional issues after enabling nosniff.
Solution: before enabling, check that all common file types receive correct MIME types
— on nginx this is handled via /etc/nginx/mime.types,
which usually fits out of the box. On Apache, no intervention is typically needed.
Bottom line
X-Content-Type-Options: nosniff is
one of the simplest security headers — no configuration options, no trade-off, just set
it. Mandatory for every website with file uploads, user-generated content or API
endpoints. In Webscan Radar you'll find this header in the list of the six checked
security headers.