CVE-2023-22898 (Python, published 2023-01-10T02:15Z)
Description: value: workers/extractor.py in Pandora (aka pandora-analysis/pandora) 1.3.0 allows a denial of service when an attacker submits a deeply nested ZIP archive (aka ZIP bomb).
Severity: nan (CVSS v3 base score: 6.5)
Weakness: CWE-20 \u2014 Improper Input Validation
The product receives input or data, but it does
        not validate or incorrectly validates that the input has the
        properties that are required to process the data safely and
        correctly.
Repository: https://github.com/pandora-analysis/pandora
Files changed:
pandora/workers/extractor.py
pandora/workers/extractor.yml.sample
Commit message: fix: Stop extractor on zip bomb (check total amount of extracted files and recursivity)


Vulnerable code:
        # wait for all the tasks to finish
        while not all(t.workers_done for t in tasks):
            time.sleep(1)

        if tasks:
            report.status = max(t.status for t in tasks)
            if report.status > Status.CLEAN:
                report.add_details('Warning', 'There are suspicious files in this archive, click on the "Extracted" tab for more.')
        elif not report.status == Status.NOTAPPLICABLE:

Fixed code:
        # Check if we reach the max recursivity (archive in archive in archive...)
        _curtask = task
        _cur_recurse = self.max_recurse
        _cur_max_files_in_recurse = self.max_files_in_recursive_archive
        while _cur_recurse > 0 and _cur_max_files_in_recurse > 0:
            if not _curtask.parent:
                break
            _curtask = _curtask.parent
            _cur_recurse -= 1
            _cur_max_files_in_recurse -= len(_curtask.extracted)

        if _cur_recurse <= 0:
            self.logger.warning(f'File {task.file.path.name} is too deep in the recursion chain (>{self.max_recurse}).')
            report.status = Status.ERROR if self.max_is_error else Status.ALERT
            report.add_details('Warning', f'File {task.file.path.name} is too deep in the recursion chain (>{self.max_recurse}). If you want to scan it anyway, click on Actions > Rescan file.')
            return

        if _cur_max_files_in_recurse <= 0:
            self.logger.warning(f'File {task.file.path.name} cannot be extracted, too many files (>{self.max_files_in_recursive_archive}) in the recursive archive.')
            report.status = Status.ERROR if self.max_is_error else Status.ALERT
            report.add_details('Warning', f'File {task.file.path.name} cannot be extracted, too many files (>{self.max_files_in_recursive_archive}) in the recursive archive. If you want to scan it anyway, click on Actions > Rescan file.')
            return


        if not tasks and not report.status == Status.NOTAPPLICABLE:
        elif report.status not in [Status.ERROR, Status.WARN, Status.ALERT, Status.OVERWRITE]:
            # wait for all the workers to finish, or have one of them raising an ALERT
            while not all(t.workers_done for t in tasks):
                for t in tasks:
                    # If any of the task is marked as ALERT or OVERWRITE, we can quit.
                    if t.workers_done and t.status >= Status.ALERT:
                        report.add_details('Warning', 'There are suspicious files in this archive, click on the "Extracted" tab for more.')
                        break
                time.sleep(1)
            report.status = max(t.status for t in tasks if t.workers_done)
  max_files_in_recursive_archive: 25
  max_recurse: 2