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 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(), 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

  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 (5)

comment:1 by sammiee5311, 4 weeks ago

Description: modified (diff)

comment:2 by sammiee5311, 3 weeks ago

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

All tests pass (requests_tests — 115 tests) under SQLite, Python 3.14, macOS.

comment:3 by Huwaiza, 3 weeks ago

Owner: set to Huwaiza
Status: newassigned

comment:4 by Huwaiza, 3 weeks ago

Owner: Huwaiza removed
Status: assignednew

comment:5 by sammiee5311, 3 weeks ago

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