#33062: Null byte in uploaded filename extension is not cleaned up, results in
exception
-----------------------------------------+------------------------
               Reporter:  Alex Vandiver  |          Owner:  nobody
                   Type:  Bug            |         Status:  new
              Component:  Forms          |        Version:  3.2
               Severity:  Normal         |       Keywords:
           Triage Stage:  Unreviewed     |      Has patch:  0
    Needs documentation:  0              |    Needs tests:  0
Patch needs improvement:  0              |  Easy pickings:  0
                  UI/UX:  0              |
-----------------------------------------+------------------------
 A >2.5M file uploaded with a raw null byte anyplace after the `.` in its
 filename means that Django attempts to create a tempfile with that same
 "extension," which errors out with `ValueError: embedded null byte`.

 It's almost certainly a violation of RFC to have a filename with a raw
 null byte in it, but it shouldn't result in a 500 when parsing the form.

 Here's code to generate a bad request:
 {{{
 #!/usr/bin/env python3
 import io

 import requests

 contents = io.StringIO("." * (1024 * 1024 * 3))

 files = {"docfile": (b"bogus.txt!", contents, "text/plain")}

 req = requests.Request("POST", "http://localhost:8000/";, files=files,
 data={})
 prepared = req.prepare()

 body = prepared.body
 assert isinstance(body, bytes)
 prepared.body = body.replace(b"!", b"\x00")

 requests.Session().send(prepared)
 }}}

 ...which produces an error with the view:
 {{{
 from django import forms
 from django.http import HttpResponseRedirect
 from django.shortcuts import render
 from django.views.decorators.csrf import csrf_exempt


 class UploadFileForm(forms.Form):
     docfile = forms.FileField()


 @csrf_exempt
 def index(request):
     if request.method == 'POST':
         form = UploadFileForm(request.POST, request.FILES)
         if form.is_valid():
             print(repr(request.FILES['docfile']))
             return HttpResponseRedirect('/')
         else:
             print("Not valid!")
             return HttpResponseRedirect('/')
     else:
         form = UploadFileForm()
     return render(request, 'uploads/index.html', {'form': form})
 }}}

 -----

 I'm not sure what the goal is of preserving the "extension" of the
 uploaded file in the tempfile that is made; if that's important enough a
 behaviour to keep, some amount of escaping on the parsed-out extension may
 be necessary.

-- 
Ticket URL: <https://code.djangoproject.com/ticket/33062>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.

-- 
You received this message because you are subscribed to the Google Groups 
"Django updates" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-updates/049.92fec8dce21c15dbbcebc85edba41ea9%40djangoproject.com.

Reply via email to