diff options
| author | Mariusz Felisiak <felisiak.mariusz@gmail.com> | 2021-01-22 12:23:18 +0100 |
|---|---|---|
| committer | Mariusz Felisiak <felisiak.mariusz@gmail.com> | 2021-02-01 09:07:36 +0100 |
| commit | 05413afa8c18cdb978fcdf470e09f7a12b234a23 (patch) | |
| tree | d3672ac9ec790440c7f4fb3984b8c3d40136c8f8 /django/utils/archive.py | |
| parent | 6822aa5c6c3fbec7c5393a05e990865ba59fe167 (diff) | |
Fixed CVE-2021-3281 -- Fixed potential directory-traversal via archive.extract().
Thanks Florian Apolloner, Shai Berger, and Simon Charette for reviews.
Thanks Wang Baohua for the report.
Diffstat (limited to 'django/utils/archive.py')
| -rw-r--r-- | django/utils/archive.py | 17 |
1 files changed, 14 insertions, 3 deletions
diff --git a/django/utils/archive.py b/django/utils/archive.py index 235809f2ad..d5a0cf0446 100644 --- a/django/utils/archive.py +++ b/django/utils/archive.py @@ -27,6 +27,8 @@ import stat import tarfile import zipfile +from django.core.exceptions import SuspiciousOperation + class ArchiveException(Exception): """ @@ -133,6 +135,13 @@ class BaseArchive: return False return True + 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): + raise SuspiciousOperation("Archive contains invalid path: '%s'" % name) + return filename + def extract(self): raise NotImplementedError('subclasses of BaseArchive must provide an extract() method') @@ -155,7 +164,7 @@ class TarArchive(BaseArchive): name = member.name if leading: name = self.split_leading_dir(name)[1] - filename = os.path.join(to_path, name) + filename = self.target_filename(to_path, name) if member.isdir(): if filename: os.makedirs(filename, exist_ok=True) @@ -198,8 +207,10 @@ class ZipArchive(BaseArchive): info = self._archive.getinfo(name) if leading: name = self.split_leading_dir(name)[1] - filename = os.path.join(to_path, name) - if filename.endswith(('/', '\\')): + if not name: + continue + filename = self.target_filename(to_path, name) + if name.endswith(('/', '\\')): # A directory os.makedirs(filename, exist_ok=True) else: |
