mirror of
				https://github.com/django/django.git
				synced 2025-10-31 09:41:08 +00:00 
			
		
		
		
	[5.2.x] Fixed CVE-2025-59682 -- Fixed potential partial directory-traversal via archive.extract().
Thanks stackered for the report. Follow up to05413afa8c. Backport of924a0c092efrom main.
This commit is contained in:
		| @@ -145,7 +145,11 @@ class BaseArchive: | ||||
|     def target_filename(self, to_path, name): | ||||
|         target_path = os.path.abspath(to_path) | ||||
|         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) | ||||
|         return filename | ||||
|  | ||||
|   | ||||
| @@ -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 | ||||
| dictionary expansion, as the ``**kwargs`` passed to these methods (follow up to | ||||
| :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`). | ||||
|   | ||||
| @@ -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 | ||||
| dictionary expansion, as the ``**kwargs`` passed to these methods (follow up to | ||||
| :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`). | ||||
|   | ||||
| @@ -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 | ||||
| :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 | ||||
| ======== | ||||
|  | ||||
|   | ||||
| @@ -3,6 +3,7 @@ import stat | ||||
| import sys | ||||
| import tempfile | ||||
| import unittest | ||||
| import zipfile | ||||
|  | ||||
| from django.core.exceptions import SuspiciousOperation | ||||
| from django.test import SimpleTestCase | ||||
| @@ -94,3 +95,21 @@ class TestArchiveInvalid(SimpleTestCase): | ||||
|             with self.subTest(entry), tempfile.TemporaryDirectory() as tmpdir: | ||||
|                 with self.assertRaisesMessage(SuspiciousOperation, msg % invalid_path): | ||||
|                     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) | ||||
|   | ||||
		Reference in New Issue
	
	Block a user