Missing X-Content-Type-Options

What it is

The X-Content-Type-Options: nosniff header tells the browser “respect the Content-Type, don’t guess it from the file’s contents”. Without it, browsers (historically Internet Explorer in particular, and others today) inspect the first few bytes and decide for themselves.

Why it’s a problem

A standard scenario — a user uploads an image to your site. Instead of a real image, the attacker uploads a file cat.jpg that internally contains HTML with a <script>. The server sensibly labels it as image/jpeg. But without nosniff, the browser inspects the contents, sees HTML, and runs that cat.jpg as a page. Uploaded XSS.

A second scenario — a CSS file into which the attacker managed to inject HTML, which the browser starts to “sensibly” render. nosniff puts an end to this.

How to fix it

Trivial. The only value is nosniff.

nginx:

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

Apache:

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

WordPress (functions.php / mu-plugin):

add_action('send_headers', function () {
    header('X-Content-Type-Options: nosniff');
});

Cloudflare: Rules → Transform Rules → HTTP Response Header Modification → add the header.

What can go wrong

Practically nothing. nosniff merely enforces the correct Content-Type — if your server sends Content-Type: text/css for .css files, you’re fine. A problem would only arise if your server sent CSS with Content-Type: text/plain — the browser would then stop rendering it. If you run into this, you’re fixing your own MIME mapping, not the header.

Verification

curl -I https://example.cz | grep -i content-type-options

References