Opened 5 hours ago
Last modified 4 hours ago
#36931 new Bug
Unhandled LookupError in multipart parser when RFC 2231 encoding name is invalid — at Version 1
| Reported by: | sammiee5311 | Owned by: | |
|---|---|---|---|
| Component: | HTTP handling | Version: | 6.0 |
| Severity: | Normal | Keywords: | multipart parser LookupError RFC2231 |
| Cc: | Triage Stage: | Unreviewed | |
| 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()](https://github.com/django/django/blob/main/django/utils/http.py#L332), [django/utils/http.py](https://github.com/django/django/blob/main/django/utils/http.py) passes the encoding to urllib.parse.unquote(), which raises LookupError.
The caller in [django/http/multipartparser.py](https://github.com/django/django/blob/main/django/http/multipartparser.py#L729) 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.