CVE-2022-39367 (Java, published 2022-10-28T16:15Z)
Description: value: QTIWorks is a software suite for standards-based assessment delivery. Prior to version 1.0-beta15, the QTIWorks Engine allows users to upload QTI content packages as ZIP files. The ZIP handling code does not sufficiently check the paths of files contained within ZIP files, so can insert files into other locations in the filesystem if they are writable by the process running the QTIWorks Engine. In extreme cases, this could allow anonymous users to change files in arbitrary locations in the filesystem. In normal QTIWorks Engine deployments, the impact is somewhat reduced because the default QTIWorks configuration does not enable the public demo functionality, so ZIP files can only be uploaded by users with "instructor" privileges. This vulnerability is fixed in version 1.0-beta15. There are no database configuration changes required when upgrading to this version. No known workarounds for this issue exist.
Severity: nan (CVSS v3 base score: 6.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/davemckain/qtiworks
Files changed:
qtiworks-engine/src/main/java/uk/ac/ed/ph/qtiworks/services/AssessmentPackageFileImporter.java
Commit message: vuln-fix: Zip Slip Vulnerability

This fixes a Zip-Slip vulnerability.

This change does one of two things. This change either

1. Inserts a guard to protect against Zip Slip.
OR
2. Replaces `dir.getCanonicalPath().startsWith(parent.getCanonicalPath())`, which is vulnerable to partial path traversal attacks, with the more secure `dir.getCanonicalFile().toPath().startsWith(parent.getCanonicalFile().toPath())`.

For number 2, consider `"/usr/outnot".startsWith("/usr/out")`.
The check is bypassed although `/outnot` is not under the `/out` directory.
It's important to understand that the terminating slash may be removed when using various `String` representations of the `File` object.
For example, on Linux, `println(new File("/var"))` will print `/var`, but `println(new File("/var", "/")` will print `/var/`;
however, `println(new File("/var", "/").getCanonicalPath())` will print `/var`.

Weakness: CWE-22: Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')
Severity: High
CVSSS: 7.4
Detection: CodeQL (https://codeql.github.com/codeql-query-help/java/java-zipslip/) & OpenRewrite (https://public.moderne.io/recipes/org.openrewrite.java.security.ZipSlip)

Reported-by: Jonathan Leitschuh <Jonathan.Leitschuh@gmail.com>
Signed-off-by: Jonathan Leitschuh <Jonathan.Leitschuh@gmail.com>

Bug-tracker: https://github.com/JLLeitschuh/security-research/issues/16

Co-authored-by: Moderne <team@moderne.io>

Vulnerable code:

Fixed code:
                if (!destFile.toPath().normalize().startsWith(importSandboxDirectory.toPath().normalize())) {
                    throw new RuntimeException("Bad zip entry");
                }