(Solved) Is this a bug or am I missing something: SuspiciousFileOperation -> Detected path traversal attempt in

Hello all,

I have a problem with relative paths while storing files.

Snipped from settings.py

if DEBUG:
    MEDIA_ROOT = BASE_DIR / "../data/"

I like to keep all uploaded files outside my source directory, even in DEBUG mode.

Snipped models.py

def directory_path(instance, filename):

    directory = os.path.join(MEDIA_ROOT, f"/files/somenumber")
    return os.path.join(directory, filename)

class myFile(models.Model):
    
    file      = models.FileField(upload_to=directory_path, null=True, max_length=300,
                                 help_text=_("Select file."))

result

SuspiciousFileOperation at /test/file/new
Detected path traversal attempt in '../data/files/somenumber/filename'

The trace end:

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

  File "lib/python3.14/site-packages/django/core/files/utils.py", line 17, in validate_file_name
    raise SuspiciousFileOperation(

Snipped for utils.py:

def validate_file_name(name, allow_relative_path=False):
    # Remove potentially dangerous names
    if os.path.basename(name) in {"", ".", ".."}:
        raise SuspiciousFileOperation("Could not derive file name from '%s'" % name)

    if allow_relative_path:
        # Ensure that name can be treated as a pure posix path, i.e. Unix
        # style (with forward slashes).
        path = pathlib.PurePosixPath(str(name).replace("\\", "/"))
        if path.is_absolute() or ".." in path.parts:
            raise SuspiciousFileOperation(
                "Detected path traversal attempt in '%s'" % name
            )
    elif name != os.path.basename(name):
        raise SuspiciousFileOperation("File name '%s' includes path elements" % name)

    return name

Now what I don’t get is, as far as I know, relative paths always have some kind of ‘..’ in them or they would be absolute paths.

But reading the code it says “yes we allow relative paths” but you can’t have any “..” in any part of the path.

How can I store files outside my source directory? What am I missing?

Django: 6.1
Pyhton: 3.14
7.1.9-1-MANJARO x86_64 GNU/Linux

This is not an accurate statement. Any path not starting with a / is a relative path - relative to whatever the current directory happens to be.

Don’t include the .. as a literal. Use the pathlib parent function to reference the parent of BASE_DIR:

MEDIA_ROOT = BASE_DIR.parent / "data"

Thanks Ken,

It works great, kinda.

I now get /path/to/my/source/data/files/somenumber/filename which where it should be as my source files are in /path/to/my/source/files.

However I still get the same error because now path.is_absolute(): True

Which makes sense as it starts with a /.

Any suggestions?

upload_to is to be relative to MEDIA_ROOT.

If MEDIA_ROOT is /path/to/my/source/data, then upload_to = f"files/somenumber". You don’t join the desired path to MEDIA_ROOT in upload_to.

Hello Ken,

Got it, thanks.

Regards.