MIME Sniffing and Content-Type Confusion: XSS Uploads That Still Work
Browsers sometimes guess content types when servers send vague or wrong Content-Type headers. Pair that with a file upload that stores an HTML/JS polyglot, and you get stored XSS on an origin that thought it was serving images.
X-Content-Type-Options: nosniff blocks many cases — when it is missing, hunters still win.
Hunt checklist
- Upload an image that also contains HTML (
GIF89a+<script>tricks, or SVG). - Observe the
Content-Typeon the download/view URL. - Check for
nosniff. - Open the URL in a browser — does script run?
Also try: wrong extensions, double extensions, Content-Type controlled by the client on upload, and CDN transforms that strip security headers.
Impact
Stored XSS on the upload/cdn origin — session theft, account takeover, or wormable payloads inside the app if cookies are scoped broadly.
Safe proof
Use a minimal script that only signals your own collector (or alert on a lab). Do not upload malware. Prefer SVG/HTML test files the program allows.
Report structure
Show the upload request, the serving response headers, and browser execution. Recommend correct Content-Type, nosniff, separate file domain, and content disposition as attachment for untrusted types.
Defensive checklist
- Always send
X-Content-Type-Options: nosniff. - Serve user uploads from a cookie-less domain.
- Sniff and re-encode images server-side; do not trust client MIME.
- Block HTML/SVG when only images are required — or sanitize SVG strictly.
- Set
Content-Disposition: attachmentfor ambiguous types.
Uploads plus sniffing equal classic stored XSS. Headers are part of the vulnerability — include them in every report.
Original Bugflare guide informed by OWASP MIME type confusion material.