Opened 2 months ago

Last modified 17 hours ago

#37081 assigned Bug

loaddata fails when a directory in the fixture path contains a dot

Reported by: Alisson Silveira Owned by: Alisson Silveira
Component: Core (Management commands) Version: dev
Severity: Normal Keywords:
Cc: Alisson Silveira Triage Stage: Accepted
Has patch: yes Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

How to reproduce:

Create a fixture in a directory containing a dot, for example:

fixtures/fix.v1/data.json

Run (without specifying the file extension):

python manage.py loaddata fixtures/fix.v1/data

This raises:

CommandError: Problem installing fixture 'fixtures/fix': v1/data is not a known serialization format.

This occurs when a directory in the fixture path contains a dot, as the full path is incorrectly split on "." instead of operating on the file name.

Expected behavior: Django should correctly determine the fixture format based on the file name and load the fixture successfully, ignoring dots in directory names.

A fix has been identified and will be submitted in a pull request.

Change History (7)

comment:1 by Alisson Silveira, 2 months ago

Owner: set to Alisson Silveira
Status: newassigned

comment:2 by Alisson Silveira, 2 months ago

Has patch: set

comment:3 by Gert Burger, 8 weeks ago

Tested this on stable/6.0.x and 5.2.11, as reported, if the fixture extension is not specified then any other dot in the path will incorrectly be considered the separator for the extension.

comment:4 by Sarah Boyce, 7 weeks ago

Triage Stage: UnreviewedAccepted

Thank you! I think this is a bug worth addressing.
My only concern was whether this could create any path traversal issues allowing something like fixtures/../secret.json but I think this would be out of the scope of security issues anyway. See https://docs.djangoproject.com/en/6.0/internals/security/#how-does-django-evaluate-a-report

comment:5 by Sarah Boyce, 7 weeks ago

Version: 6.0dev

in reply to:  4 comment:6 by Alisson Silveira, 7 weeks ago

Replying to Sarah Boyce:

Thank you! I think this is a bug worth addressing.
My only concern was whether this could create any path traversal issues allowing something like fixtures/../secret.json but I think this would be out of the scope of security issues anyway. See https://docs.djangoproject.com/en/6.0/internals/security/#how-does-django-evaluate-a-report

Thanks for your feedback, Sarah! I can provide a bit more context for the record.

I decided to use a PurePath object to prevent any filesystem access, since this method only needs to parse the filename. The filename is the only piece of information being extracted and modified from the filepath. In contrast, the current approach relies on rsplit() directly on the file path string, which could potentially introduce security issues if the path is manipulated. Using PurePath makes the intent clearer and provides safer path handling.

Since this was a bug I encountered in a production system, my fix is specifically focused on addressing that issue. However, I’d be more than happy to address any additional fixes or improvements related to this area if needed. Please let me know if you’d like me to explore any further improvements here.

in reply to:  4 comment:7 by Raffaella, 17 hours ago

Replying to Sarah Boyce:

Thank you! I think this is a bug worth addressing.
My only concern was whether this could create any path traversal issues allowing something like fixtures/../secret.json but I think this would be out of the scope of security issues anyway. See https://docs.djangoproject.com/en/6.0/internals/security/#how-does-django-evaluate-a-report

Thank you Sarah for addressing this. I was following your suggestion and I wrote this test:

from django.core.management.commands.loaddata import Command
from django.core import serializers

from django.test import SimpleTestCase

class ParseNameTests(SimpleTestCase):
    def setUp(self):
        self.command = Command()
        self.command.serialization_formats = serializers.get_public_serializer_formats()

    def test_parent_traversal_no_longer_raises(self):
        name, ser_fmt, cmp_fmt = self.command.parse_name("../secret") 
        self.assertEqual(name, "../secret")
        self.assertIsNone(ser_fmt)
        self.assertIsNone(cmp_fmt)

This test passes with the PurePath fix. Without it, parse_name("../secret") used to raise CommandError but only by accident: the dots in ".." get treated as format delimiters, triggering the same "unknown serialization format" error this ticket is about but for a different reason.
Note that a fixture name with an explicit extension, e.g. "../secret.json", is already parsed correctly even without this fix.
Even though this isn't a blocker, I think it's worth highlighting.

Note: See TracTickets for help on using tickets.
Back to Top