Django 3.2.4 Update: SuspiciousFileOperation ... Detected path traversal attempt

Hi Florian,

Thanks for helping out. I see that my path is not relative to my upload_to so based on what you write, that makes sense. The upload to is left over from earlier iterations of my code. There is a requirement that images be uploaded to AWS in a human friendly directory structure. In my code example below I demonstrate where the file path comes from.

The stacktrace is:


File "/usr/local/lib/python3.8/site-packages/django/core/handlers/base.py" line 181 in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)

File "/usr/local/lib/python3.8/site-packages/django/views/decorators/csrf.py" line 54 in wrapped_view
return view_func(*args, **kwargs)

File "/usr/local/lib/python3.8/site-packages/django/views/generic/base.py" line 70 in view
return self.dispatch(request, *args, **kwargs)

File "/usr/local/lib/python3.8/site-packages/rest_framework/views.py" line 509 in dispatch
response = self.handle_exception(exc)

File "/usr/local/lib/python3.8/site-packages/rest_framework/views.py" line 469 in handle_exception
self.raise_uncaught_exception(exc)

File "/usr/local/lib/python3.8/site-packages/rest_framework/views.py" line 480 in raise_uncaught_exception
raise exc

File "/usr/local/lib/python3.8/site-packages/rest_framework/views.py" line 506 in dispatch
response = handler(request, *args, **kwargs)

File "/code/media/views.py", line 106 in post [args] [locals]
instance = self.create_media(

File "/code/media/views.py", line 142 in create_media [args] [locals]
instance.file.save(filename, file)
- 3 non-project frames

File "/usr/local/lib/python3.8/site-packages/django/db/models/fields/files.py" line 88 in save
name = self.field.generate_filename(self.instance, name)

File "/usr/local/lib/python3.8/site-packages/django/db/models/fields/files.py" line 321 in generate_filename
filename = validate_file_name(filename, allow_relative_path=True)

File "/usr/local/lib/python3.8/site-packages/django/core/files/utils.py" line 18 in validate_file_name [args] [locals]
raise SuspiciousFileOperation(
SuspiciousFileOperation: Detected path traversal attempt in '/case_data/dogs/01000/dogs_1000_1622660073141.jpeg'

The final URL is:

https://my-bucket.s3.amazonaws.com/case_data/dogs/01000/dogs_1000_1622660073141.jpeg

I’ve added some more context to my code below.

class MediaUploadSerializer(serializers.Serializer):
    filename = serializers.CharField(max_length=64, min_length=1, required=True)
    short_name = serializers.CharField(max_length=64, min_length=1, required=True)
    annotation = serializers.CharField(max_length=1024, min_length=1, required=False)
    file = serializers.FileField(required=True)
    case = serializers.UUIDField(required=True)

class MediaCreatorView(views.APIView):
    serializer_class = serializers.MediaUploadSerializer
    model = # in this instance it an Image as in show in my first post

   def post(self, request, *args, **kwargs):
      # ...
      file = request.FILES["file"]  # FileField
      filename = serializer.validated_data.get("filename", None)  # CharField
      # ..
      # the below returns the path of where the file is stored on AWS.
      # this results in the string:
      # "/case_data/dogs/01000/dogs_1000_1622660073141.jpeg"

      filename = utils.aws_filename_key(group, case) + filename

      try:
            instance = self.create_media(
                file, filename, request.user, short_name=short_name, annotation=annotation
            )
      # ...

    def create_media(self, file, filename, user, short_name=None, annotation=None):
        try:
            instance = self.model(
                file=filename, uploaded_by=user, short_name=short_name, annotation=annotation
            )
            instance.save()
            instance.file.save(filename, file)
            return instance
        except IntegrityError:

If I have understood the problem correctly, I will need to have my file path relative to upload_to=images. Therefore I should have:

images/case_data/dogs/01000/dogs_1000_1622660073141.jpeg

instead of

/case_data/dogs/01000/dogs_1000_1622660073141.jpeg

As a test, I modified my aws key generating code to this:

filename = "images" + utils.aws_filename_key(group, case) + filename
# filename now equals: "images/case_data/dogs/01000/dogs_1000_1622660073141.jpeg"

With this small hack, I can now upload my images using 3.2.4.

Have I understood you correctly or am I still off in la la land?

Cheers,

Conor