No X-Content-Type-Options: nosniff header
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/pngwhose 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
Send the header on every response. Add
X-Content-Type-Options: nosniffat the web server, the application framework, or the CDN -- whichever sits in front of everything.Use exactly that value.
nosniffis the only value any browser acts on. Anything else is equivalent to not sending the header.Do not use a meta tag. Browsers ignore
<meta http-equiv="X-Content-Type-Options">entirely.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/plainwill stop being applied. Fix any mislabelled responses before or at the same time.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: nosniffExample 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-8Corrected 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: nosniffExample 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: sniffCorrected version:
X-Content-Type-Options: nosniffHow PixyScan detects this
Reads the response headers for the page as it was served.
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
nosnifftwice is treated as protected rather than reported.Reports when the header is absent or empty.
Reports when it is present but not
nosniff. Every comma-separated token has to benosniff; a value ofnosniff, sniffis not protection. The comparison ignores case and surrounding whitespace.Does not accept a meta tag. Only the real response header counts, because only the real response header is honoured.
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.