Skip to content
Issue docs

No X-Content-Type-Options: nosniff header

Standardx_content_type_optionsIssue 124

What is this issue?

This check reports a response that does not carry X-Content-Type-Options: nosniff.

Browsers do not always believe the Content-Type a server declares. When the declared type looks wrong, they inspect the first bytes of the response and decide for themselves what the file is -- a behaviour called MIME sniffing. nosniff turns that off: the declared type is used, and nothing else.

nosniff is the header's only defined value, so a header that is present with some other value protects nothing. Both cases are reported under this check, with the message saying which applies.

The header is honoured over HTTP as well as HTTPS, so this check runs on every page. It is also honoured only as a real response header -- a <meta http-equiv="X-Content-Type-Options"> tag does nothing, and is not accepted as delivery.

For a page to pass:

  • The response carries X-Content-Type-Options: nosniff.

Why it matters

MIME sniffing is how a file that was uploaded as an image gets executed as a script.

  • Uploaded content becomes executable. A file served as image/png whose bytes look like HTML or JavaScript can be interpreted as such, which turns any user-upload feature into a cross-site scripting vector.
  • Style and script confusion. A sniffed stylesheet or script can be loaded in a context the server never intended.
  • It is one line. No page changes, no template changes, no risk of breaking a correctly configured site.

This is a standard finding: it hardens the site, but nothing about the page stops being crawled, indexed or served without it, and there is no ranking effect. It sits alongside Referrer-Policy in severity for the same reason, and below Content-Security-Policy and the clickjacking header, which defend against attacks that need no user upload at all.

How to fix it

  1. Send the header on every response. Add X-Content-Type-Options: nosniff at the web server, the application framework, or the CDN -- whichever sits in front of everything.

  2. Use exactly that value. nosniff is the only value any browser acts on. Anything else is equivalent to not sending the header.

  3. Do not use a meta tag. Browsers ignore <meta http-equiv="X-Content-Type-Options"> entirely.

  4. Make sure your Content-Types are right first. With sniffing turned off, the declared type is what gets used -- so a stylesheet served as text/plain will stop being applied. Fix any mislabelled responses before or at the same time.

  5. Cover static assets too. Images, scripts, stylesheets and uploaded files are exactly what this protects; a rule applied only to HTML documents misses the point.

Examples

Example 1: The header sent correctly

Scenario: A server rule applied to every response.

Passes because: the header is present with its only defined value.

HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8
X-Content-Type-Options: nosniff

Example 2: No header

Scenario: A default server configuration.

Fails because: the header is absent, so a browser may ignore the declared content type and decide from the bytes.

HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8

Corrected version: add the header at the server or CDN.

HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8
X-Content-Type-Options: nosniff

Example 3: A value no browser acts on

Scenario: A header added from memory with the wrong value.

Fails because: nosniff is the only defined value, so this protects nothing while looking as though it does.

X-Content-Type-Options: sniff

Corrected version:

X-Content-Type-Options: nosniff

How PixyScan detects this

  1. Reads the response headers for the page as it was served.

  2. Flattens a repeated header. A header sent twice arrives comma-joined, or as a list on some clients. Both shapes are normalised, so a server that emits nosniff twice is treated as protected rather than reported.

  3. Reports when the header is absent or empty.

  4. Reports when it is present but not nosniff. Every comma-separated token has to be nosniff; a value of nosniff, sniff is not protection. The comparison ignores case and surrounding whitespace.

  5. Does not accept a meta tag. Only the real response header counts, because only the real response header is honoured.

  6. Runs on HTTP pages too, because MIME sniffing happens over either scheme.

What we store

Storage Level

Page Level


Database Table / Prisma Model

audit_issues.details


Stored Fields

Field Type Description
message String Whether the header was absent or carried a value no browser acts on
xContentTypeOptions String The value found, present only when it was wrong

Detection Dependencies

  • HTTP Response

Note

Kept on the finding. The PageSecurityHeader row records the headers this product has always stored (HSTS, CSP, Referrer-Policy, X-Frame-Options); adding a column for this one would need a schema change, so the value is reported on the finding instead and the absent case needs no value at all.

Further reading