All 30 checks Missing X-Content-Type-Options nosniff

Missing X-Content-Type-Options nosniff

Updated

Without X-Content-Type-Options: nosniff, a browser may look at the contents of a file and decide it is a different type from the one your server declared, which attackers can abuse to get a harmless-looking upload run as a script.

Fails: Response without the header
HTTP/2 200
content-type: text/html; charset=utf-8
cache-control: public, max-age=0
Fix: Header to add
X-Content-Type-Options: nosniff

The fix for your stack

Fix for: Next.js / Vercel

// next.config.ts
import type { NextConfig } from "next";

const nextConfig: NextConfig = {
  async headers() {
    return [
      {
        source: "/:path*",
        headers: [{ key: "X-Content-Type-Options", value: "nosniff" }],
      },
    ];
  },
};

export default nextConfig;

What content sniffing is

Servers label each file with a content type, such as text/plain or image/png. Old browsers were forgiving: if the label looked wrong, they inspected the first bytes of the file and guessed. That helped with misconfigured servers, but it created an attack. If a site lets users upload files, an attacker can upload a text file that contains script, and a browser that sniffs it as HTML or JavaScript may run it in your site's context.

The nosniff value turns that guessing off. The browser trusts the declared type, and for scripts and styles it refuses to run a file whose type does not match. It costs nothing, has almost no downside on a correctly configured site, and is part of the baseline set of security headers that scanners list. If a file suddenly stops loading after you add it, the cause is a wrong content type on that file, which is worth fixing.

How Skewcheck detects it

Skewcheck reads the response headers of the page. If x-content-type-options is present and its value is nosniff, compared without regard to capitalisation, the check passes. If the header is missing, or is set to anything else, the check fails with medium severity and removes 3 points from the score.

Only the page's own response is checked. Skewcheck does not request your images, scripts or downloads to see whether they carry the header, so set it for all paths. Header names are case-insensitive, so the lowercase form shown by HTTP/2 is the same header.

Check the live response
curl -sI https://example.com | grep -i x-content-type-options

Adding it on your platform

The fix is one line, applied to every response. The tabs above show it for nginx, Apache, Netlify, Cloudflare, Next.js, Webflow, Framer and WordPress. In nginx, use the always flag so the header also appears on error pages. In Next.js, return it from the headers function in the config file. For platforms that let you add custom response headers only on some plans, the snippet shows the route and mentions a Cloudflare proxy as an alternative when the plan does not allow it.

Some hosts already send the header by default, so check the live response before adding a duplicate. After deploying, request a few paths, not just the home page, to confirm that static files and error pages also carry it, then re-run the check.

Before and after

Before
HTTP/2 200
content-type: text/html; charset=utf-8
After
HTTP/2 200
content-type: text/html; charset=utf-8
x-content-type-options: nosniff

Check your page

Run all 30 checks on any URL. Free, no account.