Article

X-Content-Type-Options: nosniff Explained

X-Content-Type-Options: nosniff tells browsers to trust your declared Content-Type instead of MIME-sniffing the body, which can otherwise run a mislabelled file as script and cause XSS. The fix is a single header value sent on every response.

By Paul Rudenko, Security ResearcherUpdated Jul 1, 20265 min read

X-Content-Type-Options: nosniff is a small response header that tells the browser to trust the Content-Type you declared and not to second-guess it. It stops a behaviour called MIME sniffing, where a browser inspects the bytes of a response and decides to treat it as a different type than you intended — occasionally executing an uploaded or user-controlled file as a script. The header has exactly one valid value, nosniff, it has no downside, and every site should send it.

What MIME sniffing is

Every HTTP response carries a Content-Type header — for example text/html, application/json, or image/png. That header is how the browser knows what a response actually is. Historically, though, browsers did not fully trust it. If a server sent a confusing, missing, or generic type, the browser would peek at the first bytes of the body and guess the real type — a helpful behaviour when the web was full of misconfigured servers, but a risky one from a security point of view.

The problem is that a guess can override your intent. Imagine a site that lets users upload files and serves them back with a harmless type like text/plain. If the file actually contains HTML and JavaScript, a sniffing browser might decide it looks like HTML, render it, and run the script in the context of your domain. That is a stored cross-site scripting (XSS) or drive-by vector created purely by the browser overriding the declared type. The nosniff directive removes that entire class of surprise: the browser uses theContent-Type you sent and nothing else.

The real risk, in plain terms

Be clear-eyed about the size of this: MIME sniffing is a modest risk on most modern sites, not an emergency. It matters most when your site serves content that came from users or third parties — uploaded documents, avatars, exported files, or anything user-controlled that is delivered from your own origin. If any of that is mislabelled or ambiguously typed, a sniffing browser can promote it to executable HTML or JavaScript and run it as if it were part of your application. That is where the drive-by and stored-XSS scenarios live.

For a site that only serves its own static, correctly typed pages, the practical exposure is small. But the fix is a single header with no legitimate downside, so there is no reason to skip it. Sending nosniff is cheap, standard best practice — closing the door before anyone tries the handle.

For the site owner (plain English)

You do not need to understand MIME types to act on this. In everyday terms: this header tells visitors' browsers to treat each file exactly as your server labelled it, instead of guessing. Guessing is how a stray uploaded file can occasionally be tricked into running as code on your site. Turning the header on is a one-line change your developer or host applies once, it will not change how your site looks or works, and it removes a whole category of small risk. If you are not sure whether your site sends it, you can check in seconds.

Not sure if your site sends X-Content-Type-Options? Scan your headers — free and passive, no signup.

Check your security headers

The fix: one header, one value

This is the whole fix. There is exactly one valid value — nosniff — so there are no options to weigh. Send this header on every response:

X-Content-Type-Options: nosniff

Below are deployment snippets for the most common stacks. Add it once at the edge or in your server config so it covers every route.

# nginx — add to your server or location block
add_header X-Content-Type-Options nosniff always;
# Apache (mod_headers)
Header set X-Content-Type-Options nosniff
# Cloudflare — Transform Rules → Modify Response Header → Set static
# Header name:  X-Content-Type-Options
# Value:        nosniff
// Next.js — next.config.js
module.exports = {
  async headers() {
    return [
      {
        source: "/:path*",
        headers: [
          { key: "X-Content-Type-Options", value: "nosniff" },
        ],
      },
    ];
  },
};

After deploying, reload any page and confirm the header appears in the response. It should be present on HTML pages, JSON APIs, scripts, and downloads alike — there is no case where you want a response on your origin to be sniffable.

Common gotcha. nosniff is the only value this header accepts — there is no "on/off" or list of types to allow. It also only helps when your Content-Type headers are actually correct: if you serve JavaScript as text/plain, nosniff will make the browser refuse to execute it rather than guess — which is the safe outcome, but it means you must label responses accurately. Finally, this header is not a substitute for a Content Security Policy. It closes one narrow sniffing gap; CSP governs what scripts and resources are allowed to run at all.

Where it fits among headers

Judged against the wider set of security headers, X-Content-Type-Options is lower-severity than a Content Security Policy or HSTS. Those two shape how your entire site loads scripts and enforces HTTPS; nosniff addresses a single, narrower behaviour. An honest scanner reflects that: a missing X-Content-Type-Options is a hardening recommendation, not a critical finding. It is still worth fixing — it is free, universally supported, and part of every baseline — but it does not carry the urgency of a missing CSP.

Both the MDN reference for X-Content-Type-Options and the OWASP Secure Headers project list nosniff as a recommended default. Treat it as a box to tick on every site: set it once, verify it is present, and move on to the higher-impact headers.

For the full set and how they work together, read the HTTP security headers guide, and pair this with a proper Content Security Policy for real script-level protection.

Frequently asked questions

What does nosniff do?

The nosniff directive, sent as X-Content-Type-Options: nosniff, tells the browser to use the Content-Type header you declared for a response and never to guess a different type from the body. Without it, browsers may MIME-sniff — inspect the first bytes of a file and decide it is really HTML or JavaScript, then render or execute it. That guessing can turn a mislabelled or user-uploaded file served from your origin into a stored cross-site scripting (XSS) or drive-by vector. With nosniff set, the browser honours your declared type exactly, so a file you served as text or an image can never be silently promoted to executable script. It is the only value the header accepts and has no downside.

Is X-Content-Type-Options required?

It is not required for a site to function, and no standard forces it, but it is standard best practice and recommended by both MDN and the OWASP Secure Headers project. There is exactly one valid value, nosniff, it is supported by every modern browser, and it has no legitimate downside — so there is no reason not to send it. It matters most for sites that serve user-uploaded or third-party content from their own origin, where MIME sniffing could execute a mislabelled file. For a site serving only its own correctly typed pages the practical risk is modest, which is why an honest scanner treats a missing X-Content-Type-Options as a hardening recommendation rather than a critical vulnerability. Fix it anyway: it is a free one-liner.

What does X-Content-Type-Options missing mean in a scan?

An X-Content-Type-Options missing result means your server does not send the header on that response, so browsers are permitted to MIME-sniff and may treat a file as a different type than you declared. It is a low-severity hardening finding, not an active exploit — your site is not necessarily vulnerable, but you are relying on browser defaults instead of an explicit instruction. The fix is to add X-Content-Type-Options: nosniff to every response, typically once at your web server or CDN. In nginx use add_header X-Content-Type-Options nosniff always;, in Apache Header set X-Content-Type-Options nosniff, in Cloudflare a response header transform rule, and in Next.js the headers() config. Re-scan afterwards to confirm the header is present on pages, APIs, and downloads.

Related guides

See your whole external attack surface

One page is a start. The full external scan covers TLS, headers, DNS, exposed files, open services and known-exploited CVEs across your whole domain.

See the full scan →