1
0
mirror of https://github.com/django/django.git synced 2025-10-09 14:59:24 +00:00

[4.2.x] Fixed CVE-2025-59682 -- Fixed potential partial directory-traversal via archive.extract().

Thanks stackered for the report.

Follow up to 05413afa8c18cdb978fcdf470e09f7a12b234a23.

Backport of 924a0c092e65fa2d0953fd1855d2dc8786d94de2 from main.
This commit is contained in:
Sarah Boyce 2025-09-16 17:13:36 +02:00 committed by Jacob Walls
parent 38d9ef8c7b
commit 9504bbaa39
3 changed files with 32 additions and 1 deletions

View File

@ -144,7 +144,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

@ -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
@ -96,3 +97,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)