CVE-2023-48299: Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal') (CWE-22)
value: TorchServe is a tool for serving and scaling PyTorch models in production. Starting in version 0.1.0 and prior to version 0.9.0, using the model/workflow management API, there is a chance of uploading potentially harmful archives that contain files that are extracted to any location on the filesystem that is within the process permissions. Leveraging this issue could aid third-party actors in hiding harmful code in open-source/public models, which can be downloaded from the internet, and take advantage of machines running Torchserve. The ZipSlip issue in TorchServe has been fixed by validating the paths of files contained within a zip archive before extracting them. TorchServe release 0.9.0 includes fixes to address the ZipSlip vulnerability.
CWE description: 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.
CVSS v3 base score: 5.3
Published: 2023-11-21T21:15Z
Repository: https://github.com/pytorch/serve
Language: Java
Files changed: frontend/archive/src/main/java/org/pytorch/serve/archive/utils/ZipUtils.java
Commit date: 2023-09-29 23:46:40 +0000
Commit message: fix zip slip error (#2634)


Diff: diff --git a/frontend/archive/src/main/java/org/pytorch/serve/archive/utils/ZipUtils.java b/frontend/archive/src/main/java/org/pytorch/serve/archive/utils/ZipUtils.java
index c27eae64..62e625f7 100644
--- a/frontend/archive/src/main/java/org/pytorch/serve/archive/utils/ZipUtils.java
+++ b/frontend/archive/src/main/java/org/pytorch/serve/archive/utils/ZipUtils.java
@@ -26,12 +26,19 @@ public final class ZipUtils {
 
     public static void unzip(InputStream is, File dest) throws IOException {
         try (ZipInputStream zis = new ZipInputStream(is)) {
             ZipEntry entry;
             while ((entry = zis.getNextEntry()) != null) {
-                String name = entry.getName();
-                File file = new File(dest, name);
+                File file = new File(dest, entry.getName());
+                File canonicalDestDir = dest.getCanonicalFile();
+                File canonicalFile = file.getCanonicalFile();
+
+                // Check for Zip Slip vulnerability
+                if (!canonicalFile.getPath().startsWith(canonicalDestDir.getPath())) {
+                    throw new IOException("Detected Zip Slip vulnerability: " + entry.getName());
+                }
+
                 if (entry.isDirectory()) {
                     FileUtils.forceMkdir(file);
                 } else {
                     File parentFile = file.getParentFile();
                     FileUtils.forceMkdir(parentFile);
@@ -106,10 +113,18 @@ public final class ZipUtils {
                 TarArchiveInputStream tis = new TarArchiveInputStream(gzi)) {
             ArchiveEntry entry;
             while ((entry = tis.getNextEntry()) != null) {
                 String name = entry.getName().substring(entry.getName().indexOf('/') + 1);
                 File file = new File(dest, name);
+                File canonicalDestDir = dest.getCanonicalFile();
+                File canonicalFile = file.getCanonicalFile();
+
+                // Check for Zip Slip vulnerability
+                if (!canonicalFile.getPath().startsWith(canonicalDestDir.getPath())) {
+                    throw new IOException("Detected Zip Slip vulnerability: " + entry.getName());
+                }
+
                 if (entry.isDirectory()) {
                     FileUtils.forceMkdir(file);
                 } else {
                     File parentFile = file.getParentFile();
                     FileUtils.forceMkdir(parentFile);

Vulnerable code:                 String name = entry.getName();
                File file = new File(dest, name);
Fixed code:                 File file = new File(dest, entry.getName());
                File canonicalDestDir = dest.getCanonicalFile();
                File canonicalFile = file.getCanonicalFile();

                // Check for Zip Slip vulnerability
                if (!canonicalFile.getPath().startsWith(canonicalDestDir.getPath())) {
                    throw new IOException("Detected Zip Slip vulnerability: " + entry.getName());
                }

                File canonicalDestDir = dest.getCanonicalFile();
                File canonicalFile = file.getCanonicalFile();

                // Check for Zip Slip vulnerability
                if (!canonicalFile.getPath().startsWith(canonicalDestDir.getPath())) {
                    throw new IOException("Detected Zip Slip vulnerability: " + entry.getName());
                }