CVE-2016-1505 (Python, published 2016-02-03T18:59Z)
Description: value: The filesystem storage backend in Radicale before 1.1 on Windows allows remote attackers to read or write to arbitrary files via a crafted path, as demonstrated by /c:/file/ignore.
Severity: HIGH (CVSS v3 base score: 10)
Weakness: CWE-21 \u2014 DEPRECATED: Pathname Traversal and Equivalence Errors
This category has been deprecated. It was originally used for organizing weaknesses involving file names, which enabled access to files outside of a restricted directory (path traversal) or to perform operations on files that would otherwise be restricted (path equivalence). Consider using either the File Handling Issues category (CWE-1219) or the class Use of Incorrectly-Resolved Name or Reference (CWE-706).
Repository: https://github.com/Unrud/Radicale
Files changed:
radicale/pathutils.py
radicale/storage/filesystem.py
radicale/storage/multifilesystem.py
Commit message: Convert paths safely to file system paths
With the old implementation on Windows a path like
"/c:/file/ignore" got converted to "c:\file" and
allowed access to files outside of FOLDER


Vulnerable code:
    return new_path + trailing_slash
from .. import config, ical
    def _path(self):
        return os.path.join(FOLDER, self.path.replace("/", os.sep))
        return self._path + ".props"
        if not os.path.exists(os.path.dirname(self._path)):
            os.makedirs(os.path.dirname(self._path))
        with open(self._path, "w") as fd:
        os.remove(self._path)
            with open(self._path) as fd:
        abs_path = os.path.join(FOLDER, path.replace("/", os.sep))
        _, directories, files = next(os.walk(abs_path))
        abs_path = os.path.join(FOLDER, path.replace("/", os.sep))
        return os.path.isdir(abs_path)
        abs_path = os.path.join(FOLDER, path.replace("/", os.sep))
        return os.path.isfile(abs_path) and not abs_path.endswith(".props")
        modification_time = time.gmtime(os.path.getmtime(self._path))
        if not os.path.exists(self._path):
            os.makedirs(self._path)
            path = os.path.join(self._path, name)
            with filesystem.open(path, "w") as fd:
        shutil.rmtree(self._path)
        if os.path.exists(os.path.join(self._path, name)):
            os.remove(os.path.join(self._path, name))
            filenames = os.listdir(self._path)
                            % (self._path, e))
            path = os.path.join(self._path, filename)
        path = os.path.join(filesystem.FOLDER, path.replace("/", os.sep))
        return os.path.isdir(path) and not os.path.exists(path + ".props")
        path = os.path.join(filesystem.FOLDER, path.replace("/", os.sep))
        return os.path.isdir(path) and os.path.exists(path + ".props")
            os.path.getmtime(os.path.join(self._path, filename))
            for filename in os.listdir(self._path)] or [0])

Fixed code:
import os
from . import log

    return new_path + trailing_slash


def is_safe_filesystem_path_component(path):
    """Checks if path is a single component of a local filesystem path
       and is safe to join"""
    if not path:
        return False
    drive, _ = os.path.splitdrive(path)
    if drive:
        return False
    head, _ = os.path.split(path)
    if head:
        return False
    if path in (os.curdir, os.pardir):
        return False
    return True


def path_to_filesystem(path, base_folder):
    """Converts path to a local filesystem path relative to base_folder
        in a secure manner or raises ValueError."""
    sane_path = sanitize_path(path).strip("/")
    safe_path = base_folder
    if not sane_path:
        return safe_path
    for part in sane_path.split("/"):
        if not is_safe_filesystem_path_component(part):
            log.LOGGER.debug("Can't translate path safely to filesystem: %s",
                             path)
            raise ValueError("Unsafe path")
        safe_path = os.path.join(safe_path, part)
    return safe_path

from .. import config, ical, pathutils
    def _filesystem_path(self):
        return pathutils.path_to_filesystem(self.path, FOLDER)
        return self._filesystem_path + ".props"
        if not os.path.exists(os.path.dirname(self._filesystem_path)):
            os.makedirs(os.path.dirname(self._filesystem_path))
        with open(self._filesystem_path, "w") as fd:
        os.remove(self._filesystem_path)
            with open(self._filesystem_path) as fd:
        filesystem_path = pathutils.path_to_filesystem(path, FOLDER)
        _, directories, files = next(os.walk(filesystem_path))
        filesystem_path = pathutils.path_to_filesystem(path, FOLDER)
        return os.path.isdir(filesystem_path)
        filesystem_path = pathutils.path_to_filesystem(path, FOLDER)
        return (os.path.isfile(filesystem_path) and not
                filesystem_path.endswith(".props"))
        modification_time = \
            time.gmtime(os.path.getmtime(self._filesystem_path))
from .. import pathutils
        if not os.path.exists(self._filesystem_path):
            os.makedirs(self._filesystem_path)
            filesystem_path = os.path.join(self._filesystem_path, name)
            with filesystem.open(filesystem_path, "w") as fd:
        shutil.rmtree(self._filesystem_path)
        filesystem_path = os.path.join(self._filesystem_path, name)
        if os.path.exists(filesystem_path):
            os.remove(filesystem_path)
            filenames = os.listdir(self._filesystem_path)
                            % (self._filesystem_path, e))
            path = os.path.join(self._filesystem_path, filename)
        filesystem_path = pathutils.path_to_filesystem(path,
                                                       filesystem.FOLDER)
        return (os.path.isdir(filesystem_path) and
                not os.path.exists(filesystem_path + ".props"))
        filesystem_path = pathutils.path_to_filesystem(path,
                                                       filesystem.FOLDER)
        return (os.path.isdir(filesystem_path) and
                os.path.exists(path + ".props"))
            os.path.getmtime(os.path.join(self._filesystem_path, filename))
            for filename in os.listdir(self._filesystem_path)] or [0])