CVE-2018-1002209 (C++, published 2018-07-25T17:29Z)
Description: value: QuaZIP before 0.7.6 is vulnerable to directory traversal, allowing attackers to write to arbitrary files via a ../ (dot dot slash) in a Zip archive entry that is mishandled during extraction. This vulnerability is also known as 'Zip-Slip'.
Severity: MEDIUM (CVSS v3 base score: 5.5)
Weakness: CWE-22 \u2014 Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')
The product uses external input to construct a pathname that is intended to identify a file or directory that is located underneath a restricted parent directory, but the product does not properly neutralize special elements within the pathname that can cause the pathname to resolve to a location that is outside of the restricted directory.
Repository: https://github.com/stachenov/quazip
Files changed:
NEWS.txt
quazip/JlCompress.cpp
qztest/testjlcompress.cpp
Commit message: Fixed the Zip Slip vulnerability in JlCompress

When extracting a file with a dangerous path like "../evil.exe"
from a ZIP archive with JlCompress::extractDir(), the target
file would be created outside of the target directory, potentially
even overwriting an existing file there.


Vulnerable code:

    QDir directory(dir);
    QTest::newRow("simple") << "jlextdir.zip" << (
            QStringList() << "test0.txt" << "testdir1/test1.txt"
    QTest::newRow("separate dir") << "sepdir.zip" << (
            QStringList() << "laj/" << "laj/lajfile.txt");
        .count(), fileNames.count());
    foreach (QString fileName, fileNames) {
        QString fullName = "jlext/jldir/" + fileName;
        QString absolutePath = fileInfo.absoluteFilePath();
        .count(), fileNames.count());
    foreach (QString fileName, fileNames) {
        QString fullName = "jlext/jldir/" + fileName;
        QString absolutePath = fileInfo.absoluteFilePath();

Fixed code:
* Current
        * Fixed the Zip Slip vulnerability in JlCompress

    QString cleanDir = QDir::cleanPath(dir);
    QDir directory(cleanDir);
    QString absCleanDir = directory.absolutePath();
        QString absCleanPath = QDir::cleanPath(absFilePath);
        if (!absCleanPath.startsWith(absCleanDir + "/"))
            continue;
    QTest::addColumn<QStringList>("expectedExtracted");
    QTest::newRow("simple") << "jlextdir.zip"
        << (QStringList() << "test0.txt" << "testdir1/test1.txt"
            << "testdir2/test2.txt" << "testdir2/subdir/test2sub.txt")
        << (QStringList() << "test0.txt" << "testdir1/test1.txt"
    QTest::newRow("separate dir") << "sepdir.zip"
        << (QStringList() << "laj/" << "laj/lajfile.txt")
        << (QStringList() << "laj/" << "laj/lajfile.txt");
    QTest::newRow("Zip Slip") << "zipslip.zip"
        << (QStringList() << "test0.txt" << "../zipslip.txt")
        << (QStringList() << "test0.txt");
    QFETCH(QStringList, expectedExtracted);
        .count(), expectedExtracted.count());
    const QString dir = "jlext/jldir/";
    foreach (QString fileName, expectedExtracted) {
        QString fullName = dir + fileName;
        QString absolutePath = QDir(dir).absoluteFilePath(fileName);
        .count(), expectedExtracted.count());
    foreach (QString fileName, expectedExtracted) {
        QString fullName = dir + fileName;
        QString absolutePath = QDir(dir).absoluteFilePath(fileName);