Skip to content

Commit 74fa85c

Browse files
sarahboycejacobtylerwalls
authored andcommitted
[5.1.x] Fixed CVE-2025-59682 -- Fixed potential partial directory-traversal via archive.extract().
Thanks stackered for the report. Follow up to 05413af. Backport of 924a0c0 from main.
1 parent 01d2d77 commit 74fa85c

File tree

4 files changed

+40
-1
lines changed

4 files changed

+40
-1
lines changed

django/utils/archive.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,11 @@ def has_leading_dir(self, paths):
145145
def target_filename(self, to_path, name):
146146
target_path = os.path.abspath(to_path)
147147
filename = os.path.abspath(os.path.join(target_path, name))
148-
if not filename.startswith(target_path):
148+
try:
149+
if os.path.commonpath([target_path, filename]) != target_path:
150+
raise SuspiciousOperation("Archive contains invalid path: '%s'" % name)
151+
except ValueError:
152+
# Different drives on Windows raises ValueError.
149153
raise SuspiciousOperation("Archive contains invalid path: '%s'" % name)
150154
return filename
151155

docs/releases/4.2.25.txt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,11 @@ CVE-2025-59681: Potential SQL injection in ``QuerySet.annotate()``, ``alias()``,
1515
to SQL injection in column aliases, using a suitably crafted dictionary, with
1616
dictionary expansion, as the ``**kwargs`` passed to these methods (follow up to
1717
:cve:`2022-28346`).
18+
19+
CVE-2025-59682: Potential partial directory-traversal via ``archive.extract()``
20+
===============================================================================
21+
22+
The ``django.utils.archive.extract()`` function, used by
23+
:option:`startapp --template` and :option:`startproject --template`, allowed
24+
partial directory-traversal via an archive with file paths sharing a common
25+
prefix with the target directory (follow up to :cve:`2021-3281`).

docs/releases/5.1.13.txt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,11 @@ CVE-2025-59681: Potential SQL injection in ``QuerySet.annotate()``, ``alias()``,
1515
to SQL injection in column aliases, using a suitably crafted dictionary, with
1616
dictionary expansion, as the ``**kwargs`` passed to these methods (follow up to
1717
:cve:`2022-28346`).
18+
19+
CVE-2025-59682: Potential partial directory-traversal via ``archive.extract()``
20+
===============================================================================
21+
22+
The ``django.utils.archive.extract()`` function, used by
23+
:option:`startapp --template` and :option:`startproject --template`, allowed
24+
partial directory-traversal via an archive with file paths sharing a common
25+
prefix with the target directory (follow up to :cve:`2021-3281`).

tests/utils_tests/test_archive.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import sys
44
import tempfile
55
import unittest
6+
import zipfile
67

78
from django.core.exceptions import SuspiciousOperation
89
from django.test import SimpleTestCase
@@ -94,3 +95,21 @@ def test_extract_function_traversal(self):
9495
with self.subTest(entry), tempfile.TemporaryDirectory() as tmpdir:
9596
with self.assertRaisesMessage(SuspiciousOperation, msg % invalid_path):
9697
archive.extract(os.path.join(archives_dir, entry), tmpdir)
98+
99+
def test_extract_function_traversal_startswith(self):
100+
with tempfile.TemporaryDirectory() as tmpdir:
101+
base = os.path.abspath(tmpdir)
102+
tarfile_handle = tempfile.NamedTemporaryFile(suffix=".zip", delete=False)
103+
tar_path = tarfile_handle.name
104+
tarfile_handle.close()
105+
self.addCleanup(os.remove, tar_path)
106+
107+
malicious_member = os.path.join(base + "abc", "evil.txt")
108+
with zipfile.ZipFile(tar_path, "w") as zf:
109+
zf.writestr(malicious_member, "evil\n")
110+
zf.writestr("test.txt", "data\n")
111+
112+
with self.assertRaisesMessage(
113+
SuspiciousOperation, "Archive contains invalid path"
114+
):
115+
archive.extract(tar_path, base)

0 commit comments

Comments
 (0)