Opened 4 weeks ago
Last modified 2 weeks ago
#36931 closed Cleanup/optimization
Unhandled LookupError in multipart parser when RFC 2231 encoding name is invalid — at Version 5
| Reported by: | sammiee5311 | Owned by: | |
|---|---|---|---|
| Component: | HTTP handling | Version: | 6.0 |
| Severity: | Normal | Keywords: | multipart parser LookupError RFC2231 |
| Cc: | Triage Stage: | Ready for checkin | |
| Has patch: | yes | Needs documentation: | no |
| Needs tests: | no | Patch needs improvement: | no |
| Easy pickings: | yes | UI/UX: | no |
Description (last modified by )
When a multipart form upload includes an RFC 2231 encoded filename* parameter with an invalid encoding name (e.g., filename*=BOGUS''test%20file.txt), parse_header_parameters(), django/utils/http.py passes the encoding to urllib.parse.unquote(), which raises LookupError.
The caller in django/http/multipartparser.py only catches ValueError:
except ValueError: # Invalid header. continue
Since LookupError is not a subclass of ValueError, the exception propagates and results in a 500 Internal Server Error.
Steps to Reproduce
- Create a simple upload view:
from django.http import JsonResponse from django.views.decorators.csrf import csrf_exempt @csrf_exempt def upload(request): if request.method == "POST" and request.FILES: return JsonResponse({"filename": request.FILES["file"].name}) return JsonResponse({"error": "No file"}, status=400)
- Send a multipart request with a bogus encoding:
import http.client boundary = "----PoC" body = ( f"--{boundary}\r\n" f"Content-Disposition: form-data; name=\"file\"; " f"filename*=BOGUS''test%20file.txt\r\n" f"Content-Type: application/octet-stream\r\n" f"\r\n" f"content\r\n" f"--{boundary}--\r\n" ) conn = http.client.HTTPConnection("localhost", 8000) conn.request("POST", "/upload/", body=body.encode(), headers={"Content-Type": f"multipart/form-data; boundary={boundary}"}) print(conn.getresponse().status) # Returns 500
The filename must contain at least one percent-encoded character (e.g., %20) for unquote() to invoke the codec.
Confirmed on Django 6.0.2, Python 3.14.
Change History (5)
comment:1 by , 4 weeks ago
| Description: | modified (diff) |
|---|
comment:2 by , 3 weeks ago
comment:3 by , 3 weeks ago
| Owner: | set to |
|---|---|
| Status: | new → assigned |
comment:4 by , 3 weeks ago
| Owner: | removed |
|---|---|
| Status: | assigned → new |
comment:5 by , 3 weeks ago
| Description: | modified (diff) |
|---|
PR: https://github.com/django/django/pull/20714
All tests pass (requests_tests — 115 tests) under SQLite, Python 3.14, macOS.