How do I fix a missing X-Content-Type-Options header?
A missing X-Content-Type-Options header lets browsers guess a response's type from its bytes instead of trusting the declared Content-Type, which can turn an uploaded text file into executable HTML. The X-Content-Type-Options response header indicates that the MIME types advertised in Content-Type should be respected and not changed. The fix is a single header carrying the only valid value, nosniff.
Why this matters
MIME sniffing is the behavior that lets a browser render content as HTML even when the server labeled it text/plain. MDN describes two effects of nosniff: for requests whose destination is script or style, the browser blocks the response if the MIME type does not match an expected type, and for other responses it disables sniffing so the declared Content-Type is used as-is. That second effect prevents user-uploaded content from executing as an HTML document, which closes a common cross-site scripting path on sites that accept file uploads. Security testers expect this header to be set alongside a correct Content-Type on every resource, so an absent header is both a genuine weakness and a routine audit finding. It is also cheap to add: there is nothing to tune, because the specification defines exactly one meaningful value. The header is especially valuable on sites that accept file uploads and on APIs that return HTML error pages, because those responses are the ones most likely to be sniffed as a type other than the one you declared. Enforcing the declared type does not make a page safe by itself, but it removes a class of confusion in which a browser executes content its author never intended to be executable.
How to fix it
Send nosniff on all responses. The header takes no arguments and has no legitimate alternative value, so it is safe to apply globally from the edge rather than per route. The examples use Nginx add_header, Apache Header always set, Express through Helmet, the Next.js headers function, a Cloudflare Pages _headers file, and a Cloudflare Worker Response. Treat it as a companion to correctly configured Content-Type headers, because nosniff only enforces whichever type you actually send: if a resource is mislabeled, the header makes the browser honor the wrong label instead of quietly correcting it.
# Nginx
add_header X-Content-Type-Options nosniff always;
# Apache
Header always set X-Content-Type-Options "nosniff"
// Express (Helmet sets nosniff by default)
app.use(helmet());
// next.config.js
module.exports = {
async headers() {
return [
{
source: '/:path*',
headers: [ { key: 'X-Content-Type-Options', value: 'nosniff' } ],
},
]
},
}
# Cloudflare Pages public/_headers
/*
X-Content-Type-Options: nosniff
// Cloudflare Workers
export default {
async fetch() {
return new Response('ok', {
headers: { 'X-Content-Type-Options': 'nosniff' },
});
},
};
How to verify the fix
Check the header on both document responses and static assets, since a CDN rule may cover only one of them. The curl command below prints matching headers, and DevTools shows the header per request under Network. Confirm that the Content-Type of each asset is also correct, because nosniff and an accurate Content-Type work as a pair.
curl -sI https://example.com/ | grep -i x-content-type-options
Automated check
The Auditor reads your response headers and flags the absent header as a Missing X-Content-Type-Options header finding at Medium severity. It checks header presence; it does not verify that your Content-Type values are themselves correct, so confirm those separately with an HTTP inspector. Adding the header globally from the edge is usually the smallest change that clears the finding.
Scan your app free →