X-Content-Type-Options
MIME sniffing allows browsers to override declared content types, creating a security gap. The X-Content-Type-Options response header closes this gap by instructing the browser to respect the declared Content-Type.
Baseline: Widely available
The X-Content-Type-Options header is supported
across all major browsers.
webstatus.dev
Note
The "X-" naming convention for HTTP headers, "X" referring to "experimental", has been deprecated and needs to be transitioned to the formal naming convention for HTTP headers. Despite the prefix, X-Content-Type-Options is registered in the IANA permanent message headers registry and is part of the Fetch Standard. The prefix reflects its origins before formal standardization.
Usage
MIME sniffing is a browser behavior where the browser inspects the content of a response and overrides the declared Content-Type based on patterns found in the response body. While intended as a convenience for misconfigured servers, MIME sniffing opens a security gap: an attacker uploads a file disguised as an image, the browser sniffs the content as HTML or JavaScript, and a cross-site scripting attack executes.
The X-Content-Type-Options header closes this gap. When
set to nosniff, the browser strictly follows the
Content-Type header and refuses to load resources where
the declared type does not match the expected type. For
style destinations, the browser blocks the response unless
the Content-Type is text/css. For script destinations,
the browser blocks the response unless the Content-Type is a
valid JavaScript MIME type.
This header is widely deployed as a standard security hardening measure and is recommended alongside Content-Security-Policy and X-Frame-Options for defense-in-depth.
Values
nosniff
The nosniff value is the only defined value. Setting this
directive prevents the browser from MIME-sniffing a response
away from the declared Content-Type.
Example
A server delivering a JSON API response with MIME sniffing disabled, ensuring the browser treats the response strictly as JSON:
Content-Type: application/json
X-Content-Type-Options: nosniff
A CSS file served with the correct Content-Type and sniffing protection, preventing the browser from reinterpreting the file:
Content-Type: text/css
X-Content-Type-Options: nosniff
Troubleshooting
Resources blocked by nosniff produce console errors
referencing a MIME type mismatch between the declared
Content-Type and the expected type for
the resource destination.
Script blocked by MIME type mismatch. The browser logs
Refused to execute script from '...' because its MIME type ('text/plain') is not executable. This happens when the server sends a JavaScript file with a Content-Type other than a valid JavaScript MIME type (text/javascript,application/javascript). Fix the server configuration. In nginx, confirminclude mime.types;appears in thehttpblock. In Apache, verifyAddType text/javascript .jsexists in the configuration or.htaccess.CSS not applied due to wrong MIME type with nosniff. The console shows
Refused to apply style from '...' because its MIME type ('text/html') is not a supported stylesheet MIME type. The server is sending CSS files astext/htmlortext/plaininstead oftext/css. In nginx, addingtypes { text/css css; }or including the defaultmime.typesfile resolves the mismatch. In Apache, addAddType text/css .cssto the server configuration.Server sending wrong Content-Type for static files. Misconfigured servers, CDNs, or object storage (S3, GCS) often serve static files as
application/octet-streamortext/plain. Check the Content-Type of each resource using the DevTools Network tab by selecting the request and inspecting the response headers. For S3, set theContentTypemetadata on upload. For CDN-served assets, verify the origin returns the correct type since most CDNs pass through the origin's Content-Type unchanged.Diagnosing blocked resources in DevTools Console. Open the Console tab and filter for MIME-related errors. Each blocked resource message includes the URL, the declared MIME type, and the expected type. Cross-reference with the Network tab: select the blocked request, open the Headers panel, and check the
Content-Typeresponse header. The fix is always correcting the Content-Type at the server, not removing thenosniffheader.
Configuration
Apply nosniff to all responses. The overhead is
negligible and the protection covers scripts, styles,
and other subresources.
nginx:
add_header X-Content-Type-Options nosniff always;
Apache:
Header always set X-Content-Type-Options nosniff
IIS (web.config):
<customHeaders>
<add name="X-Content-Type-Options"
value="nosniff" />
</customHeaders>
See also
- Fetch Standard - X-Content-Type-Options
- Content-Type
- Content-Security-Policy
- X-Frame-Options
- HTTP headers