MIME Sniffing (Missing X-Content-Type-Options)
Updated August 8, 2026
4 min read
MIME sniffing is when a browser ignores the Content-Type a server declares and guesses the type from the response bytes instead — so a file the server labels as plain text can be treated as HTML or JavaScript. A missing X-Content-Type-Options: nosniff response header is what allows it; you detect the gap with a one-line curl check and close it by sending that header alongside correct, specific Content-Types.
What is MIME sniffing?
Every response your server sends carries a Content-Type header — text/html, application/json, image/png — telling the browser how to interpret the bytes that follow. Historically, browsers didn't fully trust it: to be forgiving of misconfigured servers, they would "sniff" the actual bytes and, if the content looked like something else, render it as that instead. A text/plain response whose body starts with <html> could be rendered as a web page.
X-Content-Type-Options: nosniff turns that guessing off. It tells the browser to honor the declared Content-Type — refusing to run a response as script, or apply it as a stylesheet, unless the type actually matches (text/javascript, text/css). When the header is absent, the browser falls back to its legacy sniffing behavior.
This maps to OWASP A05: Security Misconfiguration: a standard hardening control that ships off by default on most stacks, so it's usually just never been set.
Why it's a risk / how it's exploited
Sniffing can promote inert content into executable code inside your origin. If an attacker gets bytes that look like HTML or JavaScript into a response the browser sniffs, that content can run as script in your site's security context — a path to cross-site scripting or a drive-by.
Concrete scenario: your app lets users upload a "profile document" and serves it back from your own domain as Content-Type: text/plain. An attacker uploads a file whose body is valid HTML with an embedded <script>. Another user opens it; with no nosniff header, the browser sniffs the HTML, renders it, and runs the script under your origin — reading cookies, making authenticated requests, defacing the page.
The honest framing: this is a hardening header, not a live exploit on its own. On a static site that already sends correct, specific Content-Types, the practical risk is low — there's nothing to misinterpret. It rises when your app serves user-controlled or uploaded content, or returns text/JSON from endpoints an attacker can influence — which is why the bare finding is rated low, more urgent on sites that host uploads. It pairs with other header gaps like clickjacking protection and a Referrer-Policy.
How to detect it
Check for the header from the command line:
curl -sI https://example.com | grep -i x-content-type-options
If it prints X-Content-Type-Options: nosniff, sniffing is disabled and you're covered; if it returns nothing, the header is missing — that's the finding. You can also check in browser DevTools under Network → Response Headers.
To review this alongside your other headers in one pass, run the security headers checker. For the full picture across your site, a website vulnerability scan flags the missing header alongside the rest of your OWASP Top 10 exposure.
How to fix it
Do two things: send the header everywhere, and make sure your declared Content-Types are actually correct — nosniff is a backstop, not a substitute for the right type.
Send the header site-wide at the web server or CDN.
nginx (inside the server block):
add_header X-Content-Type-Options "nosniff" always;
Apache (mod_headers enabled):
Header always set X-Content-Type-Options "nosniff"
Reload (nginx -s reload or apachectl graceful) and re-run the curl check to confirm.
Then close the gap nosniff only backstops:
- Serve specific, correct Content-Types. Return
application/jsonfor API responses (nottext/html), the rightimage/*for media, andtext/javascript/text/cssfor scripts and styles. With accurate types, there's nothing to sniff. - Isolate user uploads. Serve user-uploaded files from a separate origin or sandbox domain, so even a sniffed-and-executed file runs outside your main site's cookies and DOM.
Caveat on nginx: add_header does not inherit into a location block that defines its own add_header directives — if you set headers per-location anywhere, repeat the nosniff line there too.
FAQ
Does nosniff alone prevent XSS from uploaded files?
No. It stops the browser from sniffing a mislabeled response into script, but a file you serve with an actual text/html Content-Type still renders. Set correct Content-Types and isolate uploads on a separate origin too.
Isn't MIME sniffing an old-browser problem that's already fixed?
No. Current browsers still fall back to content sniffing when the header is absent — nosniff is opt-in, so without it you get the legacy behavior. Sending it explicitly closes the finding and passes audits.
Not sure which of your responses ship without nosniff? Run a free website vulnerability scan to check your security headers and the rest of your web attack surface in one pass.
