Why MIME Types Are A Mess
MIME types (formally internet media types) classify content with strings like `text/html` or `application/json`, registered with IANA under the four-tree scheme of RFC 6838. In practice the system is messy: the vendor tree is bloated with proprietary identifiers, legacy quirks like the deprecation and 2022 reinstatement of `text/javascript` confuse implementers, server defaults often mislabel files, useful types are missing for many code languages, and browser MIME sniffing introduced a class of cross-site scripting risks that the `nosniff` header was created to mitigate.
Internet media types (still widely called MIME types after their origin in the 1996 Multipurpose Internet Mail Extensions spec, RFC 2045) classify content with a simple `type/subtype` string: `text/html`, `image/png`, `application/json`. The registration process is codified in RFC 6838, which carves the namespace into four trees: the standards tree (no prefix, gated by IANA expert review and usually an IETF spec), the vendor tree (`vnd.` prefix, for publicly available products), the personal/vanity tree (`prs.` prefix), and the unregistered `x.` tree for private use. On paper this is tidy. In practice the registry is a junk drawer. The vendor tree exploded. Microsoft alone registered identifiers like `application/vnd.ms-excel.sheet.macroenabled.12`, and the IANA list now carries hundreds of `application/vnd.*` entries for proprietary formats most software will never see. Legacy quirks abound. RFC 4329 (2006) deprecated `text/javascript` in favor of `application/javascript`; sixteen years later RFC 9239 (2022) reversed course and reinstated `text/javascript` as the preferred type, declaring every other JavaScript type a historical alias. Useful types are also missing: there is no widely recognized registered media type for many programming languages, leaving servers to fall back to `text/plain` or `application/octet-stream`. Server defaults compound the mess. Apache ships a `mime.types` file that has become a de-facto secondary registry, copied into nginx and other servers; out-of-date copies still mislabel `.json` as `text/plain` and `.wasm` as `application/octet-stream`. When the declared type is wrong or missing, browsers historically resorted to MIME Sniffing, inspecting the first bytes of a response to guess the format. That guess is a security hazard: an attacker who can upload a file labeled as an image but containing HTML can trick a sniffing browser into executing script, a class of bug the WHATWG mimesniff specification and the `X-Content-Type-Options: nosniff` header exist to contain. The 2018 debate around tightening browser sniffing behavior highlighted the tension: stricter rules break legacy sites, looser rules invite XSS. The result is a system where the Content-Type header is simultaneously authoritative, frequently wrong, and untrustworthy.