1
0
mirror of https://github.com/django/django.git synced 2025-10-05 12:59:10 +00:00

Fixed CVE-2025-59682 -- Fixed potential partial directory-traversal via archive.extract().

Thanks stackered for the report.

Follow up to 05413afa8c18cdb978fcdf470e09f7a12b234a23.
This commit is contained in:
Sarah Boyce 2025-09-16 17:13:36 +02:00 committed by Jacob Walls
parent 41b43c74bd
commit 924a0c092e
5 changed files with 48 additions and 1 deletions

View File

@ -145,7 +145,11 @@ class BaseArchive:
def target_filename(self, to_path, name): def target_filename(self, to_path, name):
target_path = os.path.abspath(to_path) target_path = os.path.abspath(to_path)
filename = os.path.abspath(os.path.join(target_path, name)) filename = os.path.abspath(os.path.join(target_path, name))
if not filename.startswith(target_path): try:
if os.path.commonpath([target_path, filename]) != target_path:
raise SuspiciousOperation("Archive contains invalid path: '%s'" % name)
except ValueError:
# Different drives on Windows raises ValueError.
raise SuspiciousOperation("Archive contains invalid path: '%s'" % name) raise SuspiciousOperation("Archive contains invalid path: '%s'" % name)
return filename return filename

View File

@ -15,3 +15,11 @@ CVE-2025-59681: Potential SQL injection in ``QuerySet.annotate()``, ``alias()``,
to SQL injection in column aliases, using a suitably crafted dictionary, with to SQL injection in column aliases, using a suitably crafted dictionary, with
dictionary expansion, as the ``**kwargs`` passed to these methods (follow up to dictionary expansion, as the ``**kwargs`` passed to these methods (follow up to
:cve:`2022-28346`). :cve:`2022-28346`).
CVE-2025-59682: Potential partial directory-traversal via ``archive.extract()``
===============================================================================
The ``django.utils.archive.extract()`` function, used by
:option:`startapp --template` and :option:`startproject --template`, allowed
partial directory-traversal via an archive with file paths sharing a common
prefix with the target directory (follow up to :cve:`2021-3281`).

View File

@ -15,3 +15,11 @@ CVE-2025-59681: Potential SQL injection in ``QuerySet.annotate()``, ``alias()``,
to SQL injection in column aliases, using a suitably crafted dictionary, with to SQL injection in column aliases, using a suitably crafted dictionary, with
dictionary expansion, as the ``**kwargs`` passed to these methods (follow up to dictionary expansion, as the ``**kwargs`` passed to these methods (follow up to
:cve:`2022-28346`). :cve:`2022-28346`).
CVE-2025-59682: Potential partial directory-traversal via ``archive.extract()``
===============================================================================
The ``django.utils.archive.extract()`` function, used by
:option:`startapp --template` and :option:`startproject --template`, allowed
partial directory-traversal via an archive with file paths sharing a common
prefix with the target directory (follow up to :cve:`2021-3281`).

View File

@ -17,6 +17,14 @@ to SQL injection in column aliases, using a suitably crafted dictionary, with
dictionary expansion, as the ``**kwargs`` passed to these methods (follow up to dictionary expansion, as the ``**kwargs`` passed to these methods (follow up to
:cve:`2022-28346`). :cve:`2022-28346`).
CVE-2025-59682: Potential partial directory-traversal via ``archive.extract()``
===============================================================================
The ``django.utils.archive.extract()`` function, used by
:option:`startapp --template` and :option:`startproject --template`, allowed
partial directory-traversal via an archive with file paths sharing a common
prefix with the target directory (follow up to :cve:`2021-3281`).
Bugfixes Bugfixes
======== ========

View File

@ -3,6 +3,7 @@ import stat
import sys import sys
import tempfile import tempfile
import unittest import unittest
import zipfile
from django.core.exceptions import SuspiciousOperation from django.core.exceptions import SuspiciousOperation
from django.test import SimpleTestCase from django.test import SimpleTestCase
@ -94,3 +95,21 @@ class TestArchiveInvalid(SimpleTestCase):
with self.subTest(entry), tempfile.TemporaryDirectory() as tmpdir: with self.subTest(entry), tempfile.TemporaryDirectory() as tmpdir:
with self.assertRaisesMessage(SuspiciousOperation, msg % invalid_path): with self.assertRaisesMessage(SuspiciousOperation, msg % invalid_path):
archive.extract(os.path.join(archives_dir, entry), tmpdir) archive.extract(os.path.join(archives_dir, entry), tmpdir)
def test_extract_function_traversal_startswith(self):
with tempfile.TemporaryDirectory() as tmpdir:
base = os.path.abspath(tmpdir)
tarfile_handle = tempfile.NamedTemporaryFile(suffix=".zip", delete=False)
tar_path = tarfile_handle.name
tarfile_handle.close()
self.addCleanup(os.remove, tar_path)
malicious_member = os.path.join(base + "abc", "evil.txt")
with zipfile.ZipFile(tar_path, "w") as zf:
zf.writestr(malicious_member, "evil\n")
zf.writestr("test.txt", "data\n")
with self.assertRaisesMessage(
SuspiciousOperation, "Archive contains invalid path"
):
archive.extract(tar_path, base)