Skip to content

Thumbnails/Storage sometimes not working due to Django SuspiciousFileOperation #13216

@ZuitAMB

Description

@ZuitAMB

Expected Behavior

When uploading datasets, thumbnails should be uploaded, processed and later shown correctly.

Actual Behavior

The Thumbnail cannot be created, which leads to it not being shown/rendered later on.

Steps to Reproduce the Problem

  1. (Optional) use relative paths for STATIC ROOT etc.
  2. Create/Upload a dataset
  3. See if a thumbnail is present

Specifications

  • GeoNode version: 4.4.3 (also master)
  • Installation type (vanilla, geonode-project): geonode-project
  • Installation method (manual, docker): docker
  • Platform: Azure Container Apps
  • Additional details: Stacktrace, Links, Related Tickets/Issues

Example Stack Trace taken from Celery

Detected path traversal attempt in '/usr/src/odp/volumes/statics/uploaded/thumbs/dataset-92530cb7-36a2-4c4e-be54-73d6292d292c-thumb-185ffc02-3e51-4b53-9ddc-3dde178a1309.jpg'
Traceback (most recent call last):
File "/usr/local/lib/python3.10/dist-packages/geonode/base/models.py", line 1570, in save_thumbnail
storage_manager.save(storage_manager.path(upload_path), img)
File "/usr/local/lib/python3.10/dist-packages/geonode/storage/manager.py", line 161, in save
return self._concrete_storage_manager.save(name, content, max_length=max_length)
File "/usr/local/lib/python3.10/dist-packages/geonode/storage/manager.py", line 300, in save
return self._fsm.save(name, content, max_length=max_length)
File "/usr/local/lib/python3.10/dist-packages/django/core/files/storage/base.py", line 41, in save
validate_file_name(name, allow_relative_path=True)
File "/usr/local/lib/python3.10/dist-packages/django/core/files/utils.py", line 17, in validate_file_name
raise SuspiciousFileOperation(


[2025-05-27 12:35:54,568: ERROR/ForkPoolWorker-230] Detected path traversal attempt in '/usr/src/odp/volumes/statics/uploaded/thumbs/dataset-92530cb7-36a2-4c4e-be54-73d6292d292c-thumb-185ffc02-3e51-4b53-9ddc-3dde178a1309.jpg'
Traceback (most recent call last):
File "/usr/local/lib/python3.10/dist-packages/geonode/base/models.py", line 1570, in save_thumbnail
storage_manager.save(storage_manager.path(upload_path), img)
File "/usr/local/lib/python3.10/dist-packages/geonode/storage/manager.py", line 161, in save
return self._concrete_storage_manager.save(name, content, max_length=max_length)
File "/usr/local/lib/python3.10/dist-packages/geonode/storage/manager.py", line 300, in save
return self._fsm.save(name, content, max_length=max_length)
File "/usr/local/lib/python3.10/dist-packages/django/core/files/storage/base.py", line 41, in save
validate_file_name(name, allow_relative_path=True)
django.core.exceptions.SuspiciousFileOperation: Detected path traversal attempt in '/usr/src/odp/volumes/statics/uploaded/thumbs/dataset-92530cb7-36a2-4c4e-be54-73d6292d292c-thumb-185ffc02-3e51-4b53-9ddc-3dde178a1309.jpg'
File "/usr/local/lib/python3.10/dist-packages/django/core/files/utils.py", line 17, in validate_file_name
raise SuspiciousFileOperation(
django.core.exceptions.SuspiciousFileOperation: Detected path traversal attempt in '/usr/src/odp/volumes/statics/uploaded/thumbs/dataset-92530cb7-36a2-4c4e-be54-73d6292d292c-thumb-185ffc02-3e51-4b53-9ddc-3dde178a1309.jpg'

Relevant code fragments

storage_manager.save(storage_manager.path(upload_path), img)

return self._concrete_storage_manager.save(name, content, max_length=max_length)

return self._fsm.save(name, content, max_length=max_length)

https://github.com/django/django/blob/ad28db666e0884b658f5e240c3d7ee1362688ba1/django/core/files/storage/base.py#L41
https://github.com/django/django/blob/ad28db666e0884b658f5e240c3d7ee1362688ba1/django/core/files/utils.py#L18

First Analysis on possible causes

Exception is thrown in the Django Package here: https://github.com/django/django/blob/ad28db666e0884b658f5e240c3d7ee1362688ba1/django/core/files/utils.py#L18 because it gets passed an absolute path.

To fix it, we moved to using relative paths for STATIC_ROOT, MEDIA_ROOT etc.:

STATIC_ROOT=volumes/statics/static/
MEDIA_ROOT=volumes/statics/uploaded/

and mounted to the relative path in the working directory. (Works fine)

However, we still get some of those exceptions.

Could it be related to the path being converted to an absolute one during processing around here?:

geonode/geonode/base/models.py

Lines 1546 to 1564 in 03a6578

if image:
actual_name = storage_manager.save(upload_path, ContentFile(image))
actual_file_name = os.path.basename(actual_name)
if filename != actual_file_name:
upload_path = upload_path.replace(filename, actual_file_name)
url = storage_manager.url(upload_path)
try:
# Optimize the Thumbnail size and resolution
im = Image.open(storage_manager.open(actual_name))
im = thumbnail_algorithm(im, **kwargs)
# Saving the thumb into a temporary directory on file system
tmp_location = os.path.abspath(f"{settings.MEDIA_ROOT}/{upload_path}")
im.save(tmp_location, quality="high")
with open(tmp_location, "rb+") as img:
# Saving the img via storage manager
storage_manager.save(storage_manager.path(upload_path), img)

Related tickets/exceptions

#12862

Metadata

Metadata

Labels

Type

No type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions