skip to content

What does `X-Content-Type-Options: nosniff` tell a browser to do with a response's declared Content-Type?

level: juniorimportance: must knowfreq 58%

answer

  1. stops the guess, keeps the declaration
  2. supplied type versus computed type
  3. one defined value, case-insensitive
  4. only the first value is read
  5. mis-declared assets now fail loudly

basics

~20 s

It sets the no-sniff flag, so the browser takes the declared Content-Type as the computed type instead of guessing one from the response bytes. nosniff is the only defined value, matched without regard to ASCII case.

solid answer

~50 s

`X-Content-Type-Options` is a **response** header with one defined value, `nosniff`, matched ASCII case-insensitively, and only the first value in the field is read. It does two distinct things. First, it sets the **no-sniff flag**, so the **computed MIME type** follows the **supplied MIME type** — the `Content-Type` the response actually declared — instead of being inferred from the leading bytes. An uploaded evidence file served as `text/plain` therefore stays plain text even if its bytes begin with markup. Second, in the fetch layer it turns on a block for a narrow set of destinations whose declared type does not match what the destination requires. The cost is that your declared types now have to be right: once the browser stops guessing, a stylesheet or script served with the wrong type fails instead of quietly working.

code

http · 5 lines
http
HTTP/1.1 200 OK
Content-Type: text/plain; charset=utf-8
X-Content-Type-Options: nosniff

<html><body>Appeal evidence, filed 2026-03-04</body></html>

go deeper

for a junior

Recall that it is a response header with one value, and that it makes the browser trust the declared Content-Type instead of guessing from the bytes.

for a middle

Explain supplied versus computed MIME type, the no-sniff flag, and the practical cost: once guessing stops, every mis-declared asset fails instead of working by accident.

for a senior

Show how you would turn it on across a service that also serves user uploads: fixing declared types first, and knowing which destinations begin to fail.

for a principal

Weigh a header with an immediate functional blast radius against a long tail of mis-typed assets, and decide who owns declaring types correctly across teams.

## Supplied type, computed type The MIME Sniffing standard uses two terms that this header sits directly on top of. The **supplied MIME type** is what the response declared in `Content-Type`. The **computed MIME type** is what the browser decides the resource actually is, after running an algorithm that may look at the leading bytes of the body. Sniffing exists because the web is full of responses whose declared type is missing, generic or simply wrong, and browsers that refused to guess lost to browsers that guessed well. Guessing has a price. If a server stores a file an appellant uploaded as evidence and serves it back with a generic or absent type, the bytes decide what it becomes — and a file whose bytes begin with markup can be treated as a document rather than as the upload it is. That is the failure `nosniff` exists to close. ## What the header actually sets `X-Content-Type-Options: nosniff` sets the **no-sniff flag** for that response. With the flag set, the computed MIME type follows the supplied one rather than the bytes. Three parsing details are worth carrying: - `nosniff` is the **only** defined value; nothing else turns the behaviour on, and a truthy-looking `1` does nothing. - The match is **ASCII case-insensitive**, so the spelling may vary in case but not in shape. - If the field carries several values, **only the first is read**. The flag also changes the unknown-type path. When the supplied type is missing or is one of the unknown types — `unknown/unknown`, `application/unknown`, `*/*` — the algorithm still sniffs, because there is nothing to honour; but with the no-sniff flag set it will not conclude a scriptable type such as markup. And the sniffing that does happen reads only a bounded prefix of the body, the **resource header**, of up to **1445** bytes. ## What you get, and what it costs What you get, in one sentence: the type you declared is the type the browser uses. What it costs is the part teams discover in production. Once the browser stops guessing, every mis-declared response stops working instead of working by accident: - a stylesheet served with a type whose essence is not `text/css` no longer applies; - a script served with a type that is not a JavaScript MIME type no longer runs; - a static-asset route that declared a generic type for everything starts breaking selectively, by destination. On a portal that serves a mixture of application assets and files appellants uploaded, that is the work `nosniff` creates: the upload route has to declare an accurate type, because now it is the declaration that decides. ## Where it does not help Two boundaries keep candidates honest: 1. `nosniff` pins the computed type to the **declared** type. It does not improve the declared type, and it does not make a response safer that you yourself declared as markup. A supplied markup or XML type is handled before the flag is even consulted. 2. `nosniff` does not turn a response into a download, and it does not inspect content for anything. It is a statement about type determination, not a filter. ## Where the header is set It is a response header, so it is set wherever responses are produced or passed through: in the application's own response pipeline, or once for everything at whatever terminates or proxies the connection. Because it is a single fixed value with no per-route variation, setting it once for every response is the usual choice — and unlike most hardening headers, it has an immediate functional consequence, so it is worth turning on before you have a long tail of mis-declared assets rather than after. ## Saying it in an interview Name the direction (a response header), the single value, and the effect: the declared type is used instead of one guessed from the bytes. Then give the concrete case — an upload that would otherwise be sniffed into markup — and then the cost, which is that your own mis-typed assets begin to fail loudly. An answer that stops at 'it stops MIME sniffing' is a checklist answer; the cost sentence is what shows you have shipped it.

  • A stylesheet stopped applying the day `nosniff` was switched on. What is the likely cause?
    It is served with a type whose essence is not `text/css`. Before the header, the browser could compute a usable type from the bytes; with the no-sniff flag set, the declared type stands and a style destination whose type does not match is refused. The fix is on the server: declare the right type.
  • What does `nosniff` do when the response declares an unknown type such as `application/unknown`?
    There is nothing useful to honour, so the algorithm still sniffs; but with the no-sniff flag set it will not conclude a scriptable type such as markup. You get a determination made from the bytes with the dangerous outcomes excluded, rather than no determination at all.
  • Does `X-Content-Type-Options: NOSNIFF, something-else` turn the behaviour on?
    Yes. The match is ASCII case-insensitive, so the case does not matter, and only the first value in the field is read, so the trailing token is ignored. A value that is not `nosniff` in any case, such as `1`, turns nothing on.

saying these in an interview costs you the question

  • Says nosniff makes a response download instead of render.
  • Thinks nosniff blocks every response whose declared type is wrong.
  • Believes the bytes still win when a type is declared.
  • Treats nosniff as a content filter that inspects the body.
  • Assumes any truthy value such as 1 enables it.