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 sammiee5311)

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

  1. 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)
    
  2. 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.

PR link: https://github.com/django/django/pull/20714

Change History (1)

comment:1 by sammiee5311, 4 hours ago

Description: modified (diff)
Note: See TracTickets for help on using tickets.
Back to Top