X-Content-Type-Options Header Explained: Stop MIME Sniffing
The x-content-type-options header explained with real examples, browser behavior, server configs, and the exact way to test it on your site.
If you've ever run a security scan against your site and seen a warning about a missing X-Content-Type-Options header, you've probably wondered whether it actually matters or if it's just another checkbox auditors love to flag. The short answer: it matters, it's trivial to add, and skipping it leaves a real attack surface open in older browser contexts and certain content-handling edge cases that still exist today.
What X-Content-Type-Options Actually Does
The X-Content-Type-Options header has exactly one valid value: nosniff. When a browser sees this header on a response, it stops trying to guess the file type based on the content itself and trusts only the Content-Type header the server declared.
Without it, browsers historically used a technique called MIME sniffing — looking at the first few bytes of a file to decide what it really is. Helpful when servers misconfigured their MIME types in 2005. Dangerous now, because it allows a file you intended to serve as text/plain to be interpreted as text/html or application/javascript if it happens to contain matching byte patterns.
The attack pattern
- An attacker uploads a file to your site — say a user avatar or document attachment.
- The file is named
profile.pngbut its bytes are actually crafted HTML containing JavaScript. - Your server returns it with
Content-Type: image/png. - A browser without
nosniffprotection sniffs the bytes, decides it's HTML, and executes the embedded script in your domain's context.
That's a stored XSS via MIME confusion. The nosniff directive shuts this down by forcing the browser to honor your declared type, even if the bytes don't match.
The Exact Syntax
There is only one correct way to send it:
X-Content-Type-Options: nosniffThat's it. No other values are defined. Don't bother with X-Content-Type-Options: none or anything custom — browsers ignore anything except nosniff.
What it affects in modern browsers
- Scripts: Browsers refuse to execute a response as JavaScript unless its MIME type is a JavaScript type (
text/javascript,application/javascript, etc.). - Stylesheets: In strict mode (which all modern browsers use), CSS files must be served as
text/cssor they won't load. - Images, fonts, and media: Type confusion is blocked, reducing the surface for tricks like loading a malicious SVG as an image.
Adding It to Your Server
Nginx
add_header X-Content-Type-Options "nosniff" always;Place this in your server or http block. The always flag ensures it's sent even on error responses like 404 and 500 — important because attackers often target error pages.
Apache
Header always set X-Content-Type-Options "nosniff"Add this in your .htaccess or main config. Make sure mod_headers is enabled.
Express (Node.js)
Use Helmet, which adds this header by default along with other sensible security headers:
const helmet = require('helmet');
app.use(helmet.noSniff());Cloudflare and other CDNs
You can set this as a Transform Rule or in the Modify Response Header section. If you're on Cloudflare Pages or Workers, return it directly from your worker response.
IIS
<httpProtocol>
<customHeaders>
<add name="X-Content-Type-Options" value="nosniff" />
</customHeaders>
</httpProtocol>Common Mistakes That Break Things
Adding nosniff is safe for almost every site, but a few configurations break in predictable ways:
- Serving JavaScript with the wrong MIME type. If your server returns
.jsfiles astext/plainorapplication/octet-stream, browsers will refuse to execute them oncenosniffis on. Fix theContent-Type, don't remove the header. - CSS files served as
text/html. Common when a framework serves a 404 page instead of a real stylesheet. Withnosniff, the stylesheet is blocked. Check your routing. - Dynamic endpoints returning JSON without setting
application/json. Browsers won't sniff it into something usable. Always set the type explicitly. - PDF and download endpoints. Make sure you set
Content-Type: application/pdfandContent-Disposition: attachmentwhere appropriate.
If something breaks after enabling nosniff, the fix is almost always upstream: correct the MIME type your server is sending, don't disable the protection.
Verifying It's Actually Live
The header has to be present on every response you care about — not just the homepage. Static assets, API endpoints, error pages, and uploaded content all matter. The fastest way to check is to run your URLs through the AXOX Hub HTTP Header Checker, which shows you the full response header set for any URL and highlights missing security headers including X-Content-Type-Options.
You can also verify manually with curl:
curl -I https://yourdomain.com/ | grep -i x-content-typeThings worth checking specifically:
- Main HTML responses
- JavaScript bundle URLs
- API endpoints returning JSON
- User-uploaded file URLs (avatars, attachments)
- 404 and 500 error responses
That last one catches a lot of teams off guard. If your error pages don't carry the header, an attacker who can trigger a 500 with controlled content has an opening.
Where It Fits Among Other Security Headers
On its own, X-Content-Type-Options: nosniff blocks one specific class of attack. It works best as part of a layered set:
- Content-Security-Policy — restricts what scripts and resources can load.
- Strict-Transport-Security — forces HTTPS connections.
- X-Frame-Options or CSP
frame-ancestors— prevents clickjacking. - Referrer-Policy — controls how much URL information leaks to other origins.
- Permissions-Policy — restricts browser feature access.
Of all of these, X-Content-Type-Options is the cheapest to add. There's no policy to craft, no allowlist to maintain, no risk of accidentally breaking third-party scripts. One line of config, one value, and it's done.
Run your domain through the HTTP Header Checker at AXOX Hub to see exactly which security headers are present, which are missing, and what each response looks like across your site — free, no signup.
Try the free tool
Open Tool