X-Content-Type-Options: nosniff

Responses lack X-Content-Type-Options: Nosniff, so browsers may guess a content type and execute a file as script or style when the server said it was something else.

Do this: Send X-Content-Type-Options: Nosniff on every response. Browsers may sniff an uploaded text file as JavaScript and run it in your origin.
PassX-Content-Type-Options: nosniff is present.
LowX-Content-Type-Options: nosniff is missing.

The fix, in one snippet

Example to adapt Any server
X-Content-Type-Options: nosniff

Illustrative values. Change the paths, hostnames and options to match your own site before using it.

The sections below explain what is tested, why it matters and the alternatives.

What we test

Scan.now reads the X-Content-Type-Options header on the response to / and on the first few same-origin script and stylesheet responses it fetches while parsing the page. The check passes when the value is exactly nosniff (compared case-insensitively) on the page response; it fails when the header is absent or carries any other value. Because the header matters most on non-HTML resources, the report lists any fetched asset that lacked it, and it separately notes assets served with a missing or generic Content-Type such as application/octet-stream, which is where sniffing actually engages. This is a low-severity, one-line fix, and it is included in the default output of Helmet and of Cloudflare's managed security headers. The broader picture is in the security headers guide.

Why it matters

When a Content-Type is missing or looks wrong, browsers historically inspected the bytes and guessed. That behaviour turns any user-upload feature into a script host: an attacker uploads a file that begins like an image but contains JavaScript, then references it from another page with <script src>; a browser that sniffs may execute it in the context of your origin. With nosniff, the browser refuses to run a script unless the response has a JavaScript MIME type, and refuses to apply a stylesheet that is not text/css. The header is also a prerequisite for Chrome's Cross-Origin Read Blocking, which stops cross-origin pages from pulling your HTML, JSON and XML into their process where Spectre-class attacks could read them. Both protections cost nothing if your MIME types are correct, which the same header also forces you to verify.

How to fix it

Add the header to every response, including static assets and errors. nginx (put it in the server block so it applies to all locations; note that a nested add_header in a location replaces the inherited set, so repeat it there if needed):

add_header X-Content-Type-Options "nosniff" always;

Apache:

Header always set X-Content-Type-Options "nosniff"

Express with Helmet (helmet() sets it by default; the individual middleware is helmet.noSniff()). ASP.NET Core: app.Use(async (ctx, next) => { ctx.Response.Headers["X-Content-Type-Options"] = "nosniff"; await next(); });. On Cloudflare, Rules > Settings > Managed Transforms > Add security headers includes it. After enabling, check the browser console for blocked resources: a stylesheet served as text/plain or a module served as application/octet-stream will now be refused, which is the header doing its job and a sign that the server's mime.types mapping needs a fix.

Where this fits

X-Content-Type-Options: nosniff is check 9 of 13 that the website vulnerability scanner runs under http security headers, ordered the way they are worth fixing. That ordering is the point: Fixing this one while the check above it still fails buys less than it looks like.

Fix this one first

Above it in the same category sits Server version disclosure (low), where the Server header reveals the exact web server software and version, such as Apache/2.4.58 (Ubuntu) or nginx/1.24.0, which lets attackers and bots match it to known vulnerabilities without any probing. An attacker who has that does not need this, so it is the better use of the same hour.

What fixing this still leaves open

X-Content-Type-Options: nosniff closes one route in. Immediately below it: X-Powered-By technology disclosure, where an X-Powered-By or similar header announces the application platform and often its version (PHP/8.1.2, ASP.NET, Express), narrowing an attacker's search for applicable exploits; Cache-Control on pages that set cookies, where a response that sets cookies, and is therefore personalised, does not tell caches to keep out; Cross-Origin-Resource-Policy, where responses do not carry Cross-Origin-Resource-Policy, so other origins may embed them as scripts, images or fetches in no-cors mode and pull them into their process.

Found in the same scan

The website vulnerability scanner reports this alongside checks from other categories that are at least as serious, including Certificate chain and hostname validation, where the certificate presented for this hostname did not validate: The chain does not reach a trusted root, an intermediate is missing, the name does not match, or the certificate is self-signed or expired, and Exposed .env configuration file, where a .env configuration file is served from the web root. A single run of website vulnerability scanner answers all of them at once.

Prompt for an AI Hand this check to an assistant Sign in to copy it
The first few lines
You are a senior web engineer. I ran a security and SEO scanner against my site and it reported the finding below. Fix it properly rather than suppressing the symptom.

Finding: X-Content-Type-Options: nosniff (low severity)
Scanner check id: x-content-type-options
17 more lines, including the evidence and the exact fix

The rest of this prompt names the pages and line numbers we found the problem on, the configuration to change, and the constraints a good answer has to respect. It is free, it just needs an account so the work is not scraped wholesale.

Sign in with Google

Signing in is free and takes one click. We store your email address and nothing else.

References

  1. MDN: X-Content-Type-Options
  2. WHATWG MIME Sniffing Standard
  3. OWASP HTTP Security Response Headers Cheat Sheet

Related guides