blueredix logo
low missing-x-content-type-options

X-Content-Type-Options not set

Without this small instruction, browsers can occasionally guess that a file you served — say, an uploaded image — is actually a script and execute it. The fix is one line.

What this means in plain English

When your server sends a file to a browser, it labels the file with what kind of content it contains — image, text, PDF, JavaScript, and so on. By default, browsers don’t fully trust that label: if the file doesn’t look like its label, the browser will sometimes re-guess and re-classify it. That’s called MIME sniffing.

Sounds harmless, but it isn’t always. If your site lets people upload files (avatars, attachments, comments rendered as text) and serves them back, an attacker can craft a file that looks like a normal image and parses as runnable code. Without the X-Content-Type-Options: nosniff instruction, the browser may decide it looks more like code than an image and execute it as such.

Your site doesn’t currently send the nosniff instruction.

Why it matters to your business

Two practical scenarios where this matters:

  • User-uploaded content. Profile pictures, attachments, uploaded SVG logos. If your site serves these from your domain, an attacker who uploads a crafted file can get their code to run in the next visitor’s browser.
  • Logs and unusual files. Plain-text files containing certain byte patterns can also be re-classified by older browsers. Less common today but still a real edge case.

The fix has zero downside on a properly-configured site. If your site needs the browser to guess at file types to function, that’s a separate bug worth fixing — nosniff simply tells the browser to trust your labels.

How to fix it

Add a single instruction to every response. Whoever runs your web server can do this in one line:

nginx:

add_header X-Content-Type-Options nosniff always;

Apache:

Header always set X-Content-Type-Options nosniff

Caddy:

header X-Content-Type-Options nosniff

Verify with curl -I https://your-domain.example/ — the header should appear in the output.

While you’re there, also confirm your file-upload handling does the right thing:

  1. Serve uploaded files from a separate subdomain if the risk warrants it (uploads.your-domain.example rather than the main domain). Different subdomain = no shared cookies = an attacker can’t reach the rest of your site even if they slip something through.
  2. Set explicit content types and Content-Disposition: attachment on user-uploaded files unless the file type is one you specifically want browsers to display inline.

Further reading