security
xss
ai_generated
true
XSS attack succeeds via uploaded file because browser sniffs content type instead of respecting Content-Type header
ID: security/content-type-sniffing-xss
90%Fix Rate
92%Confidence
3Evidence
2023-01-01First Seen
Version Compatibility
| Version | Status | Introduced | Deprecated | Notes |
|---|---|---|---|---|
| any | active | — | — | — |
Root Cause
Browsers may ignore Content-Type header and 'sniff' the actual content. A file served as text/plain but containing <script> tags may be executed as HTML. The X-Content-Type-Options: nosniff header prevents this but is often missing.
genericWorkarounds
-
95% success Add X-Content-Type-Options: nosniff header to all responses
response.headers['X-Content-Type-Options'] = 'nosniff' # prevents MIME sniffing
-
92% success Serve user uploads from a separate domain/subdomain
Serve from uploads.example.com, not example.com. Same-origin policy prevents uploaded content from accessing main site cookies/data.
-
88% success Set Content-Disposition: attachment for all user-uploaded files
response.headers['Content-Disposition'] = 'attachment' # forces download instead of rendering
Dead Ends
Common approaches that don't work:
-
Serve user-uploaded files with correct Content-Type and assume safety
88% fail
Without nosniff header, browsers may override Content-Type based on content analysis. A .txt file with HTML content may be rendered as HTML.
-
Validate file extension to prevent malicious uploads
82% fail
Extension validation is trivially bypassed. A file named 'image.png' can contain HTML/JS. Content-Type from extension doesn't prevent sniffing.