XSS via malicious file upload with Content-Disposition bypass
ID: security/xss-via-malicious-file-upload-with-content-disposition-bypass
Version Compatibility
| Version | Status | Introduced | Deprecated | Notes |
|---|---|---|---|---|
| Apache Tomcat 9.0.70 | active | — | — | — |
| Spring Boot 2.7.10 | active | — | — | — |
| Nginx 1.24.0 | active | — | — | — |
| IIS 10.0 | active | — | — | — |
Root Cause
When a file upload endpoint returns user-supplied filenames in the Content-Disposition header without proper sanitization, an attacker can inject script code that executes in the browser when the file is downloaded.
generic中文
当文件上传端点在Content-Disposition头中返回用户提供的文件名而未进行适当清理时,攻击者可以注入脚本代码,在下载文件时在浏览器中执行。
Official Documentation
https://owasp.org/www-community/attacks/xss/Workarounds
-
90% success Sanitize the filename by stripping all non-alphanumeric characters except dots and hyphens. Example in Python: import re; safe_filename = re.sub(r'[^a-zA-Z0-9._-]', '', original_filename). Then set Content-Disposition to attachment; filename="safe_filename" and ensure Content-Type is correct.
Sanitize the filename by stripping all non-alphanumeric characters except dots and hyphens. Example in Python: import re; safe_filename = re.sub(r'[^a-zA-Z0-9._-]', '', original_filename). Then set Content-Disposition to attachment; filename="safe_filename" and ensure Content-Type is correct.
-
95% success Use a random UUID as the filename on the server and store the original filename in a database, never returning it in headers. Example: response.setHeader('Content-Disposition', 'attachment; filename="' + uuid + '"');
Use a random UUID as the filename on the server and store the original filename in a database, never returning it in headers. Example: response.setHeader('Content-Disposition', 'attachment; filename="' + uuid + '"'); -
85% success Add Content-Security-Policy header with 'sandbox' directive for file download endpoints to prevent script execution.
Add Content-Security-Policy header with 'sandbox' directive for file download endpoints to prevent script execution.
中文步骤
Sanitize the filename by stripping all non-alphanumeric characters except dots and hyphens. Example in Python: import re; safe_filename = re.sub(r'[^a-zA-Z0-9._-]', '', original_filename). Then set Content-Disposition to attachment; filename="safe_filename" and ensure Content-Type is correct.
Use a random UUID as the filename on the server and store the original filename in a database, never returning it in headers. Example: response.setHeader('Content-Disposition', 'attachment; filename="' + uuid + '"');Add Content-Security-Policy header with 'sandbox' directive for file download endpoints to prevent script execution.
Dead Ends
Common approaches that don't work:
-
65% fail
Sanitizing the filename by removing only script tags is insufficient because attackers can use event handlers like onerror or encode characters to bypass filters.
-
55% fail
Setting Content-Type to application/octet-stream does not prevent XSS if the browser sniffs the content type or if the filename contains script that executes on download.
-
50% fail
Using a whitelist of allowed extensions is bypassed if the filename contains script in the parameter string (e.g., file.html?script=alert(1)).