Skip to main content

X-Content-Type-Options is set

ab-002531 · site-health-check.security-posture.x-content-type-options
Severity: lowactive

Why it matters

Browsers with MIME sniffing enabled attempt to guess a file's content type by reading its bytes, ignoring the Content-Type header. Attackers exploit this to serve malicious payloads in files uploaded or hosted as innocuous types — a file labeled text/plain containing JavaScript can be executed as a script. This crosses directly into CWE-79 (XSS) territory and OWASP A03 (Injection). The X-Content-Type-Options: nosniff header is a single-line fix that disables this guessing. It costs nothing to send and eliminates an entire class of content-type confusion attacks on every browser that honors it, which is all major browsers.

Severity rationale

Low because MIME sniffing attacks require an attacker-controlled upload or hosting vector, making exploitation dependent on other weaknesses being present first.

Remediation

Add the X-Content-Type-Options: nosniff header to all responses. This is a single directive with no configuration options:

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

In Next.js next.config.js:

{ key: 'X-Content-Type-Options', value: 'nosniff' }

Most CDNs (Vercel, Cloudflare) also expose this as a toggle in their security settings dashboard. Confirm with curl -sI https://yoursite.com | grep -i x-content-type.

Detection

  • ID: site-health-check.security-posture.x-content-type-options

  • Severity: low

  • What to look for: Count the occurrences of X-Content-Type-Options in the response headers. At least 1 response must include this header. Extract the header value and verify it is exactly the string nosniff (case-insensitive).

  • Detector snippet (shell-capable tools only): If curl is available, fetch HEAD against $BASE_URL and inspect the response headers for X-Content-Type-Options. If present with value nosniff, pass. If missing, fail. Exit >=2 / command not found — fall back to prose reasoning.

    curl -sS -I $BASE_URL/
    
  • Pass criteria: Exactly 1 X-Content-Type-Options header is present in the response and its value is nosniff. The value must not contain extra directives or trailing characters beyond nosniff.

  • Fail criteria: Header is missing from the response, or the value is set to something other than nosniff.

  • Skip (N/A) when: The response is a redirect (3xx status) rather than a final document response, since headers on intermediate redirects are not delivered to the browser.

  • Detail on fail: "No X-Content-Type-Options header — browsers may MIME-sniff responses"

  • Remediation: This header prevents browsers from guessing (MIME-sniffing) the content type, which can lead to XSS attacks. It requires only a single header:

    X-Content-Type-Options: nosniff
    

    In nginx: add_header X-Content-Type-Options "nosniff" always;. In Next.js next.config.js, add it to the headers() array. Most CDNs (Vercel, Cloudflare) also provide this as a toggle in their dashboard.

External references

Taxons

History