#33062 closed Bug (fixed)
File upload crash when a file extension contains null characters.
Reported by: | Alex Vandiver | Owned by: | Hrushikesh Vaidya |
---|---|---|---|
Component: | File uploads/storage | Version: | 3.2 |
Severity: | Normal | Keywords: | |
Cc: | Florian Apolloner | 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
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.
Change History (13)
comment:1 by , 3 years ago
comment:2 by , 3 years ago
Cc: | added |
---|---|
Component: | Forms → File uploads/storage |
Summary: | Null byte in uploaded filename extension is not cleaned up, results in exception → File upload crash when a file extension contains null characters. |
Triage Stage: | Unreviewed → Accepted |
Thanks for the detailed report! I'd remove null characters in MultiPartParser.sanitize_file_name()
.
comment:3 by , 3 years ago
Owner: | changed from | to
---|---|
Status: | new → assigned |
comment:5 by , 3 years ago
Owner: | removed |
---|---|
Status: | assigned → new |
comment:6 by , 3 years ago
Owner: | set to |
---|---|
Status: | new → assigned |
comment:7 by , 3 years ago
Easy pickings: | set |
---|---|
Owner: | changed from | to
comment:9 by , 3 years ago
Patch needs improvement: | unset |
---|---|
Triage Stage: | Accepted → Ready for checkin |
follow-up: 12 comment:11 by , 3 years ago
Thanks for the fix! Do you intend to backport this to the 3.2 LTS series?
comment:12 by , 3 years ago
Replying to Alex Vandiver:
Thanks for the fix! Do you intend to backport this to the 3.2 LTS series?
The issue has been present since the feature was introduced. Per our backporting policy this means it doesn't qualify for a backport to 3.2.x or 4.0.x anymore. See Django’s release process for more details.
Oh, and for completeness, this is the traceback: