VYPR
Critical severity9.8NVD Advisory· Published Jan 29, 2025· Updated Apr 15, 2026

CVE-2025-0851

CVE-2025-0851

Description

A path traversal issue in ZipUtils.unzip and TarUtils.untar in Deep Java Library (DJL) on all platforms allows a bad actor to write files to arbitrary locations.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
ai.djl:apiMaven
< 0.31.10.31.1

Patches

2
7415cc5f72aa

[api] fix issue in Tar/Zip Utils that resulted in incorrect artifact extraction (#3544)

https://github.com/deepjavalibrary/djlSiddharth VenkatesanNov 27, 2024via ghsa
12 files changed · +49 24
  • api/src/main/java/ai/djl/util/TarUtils.java+2 4 modified
    @@ -48,10 +48,8 @@ public static void untar(InputStream is, Path dir, boolean gzip) throws IOExcept
             try (TarArchiveInputStream tis = new TarArchiveInputStream(bis)) {
                 TarArchiveEntry entry;
                 while ((entry = tis.getNextEntry()) != null) {
    -                String entryName = ZipUtils.removeLeadingFileSeparator(entry.getName());
    -                if (entryName.contains("..")) {
    -                    throw new IOException("Malicious zip entry: " + entryName);
    -                }
    +                String entryName = entry.getName();
    +                ZipUtils.validateArchiveEntry(entryName, dir);
                     Path file = dir.resolve(entryName).toAbsolutePath();
                     if (entry.isDirectory()) {
                         Files.createDirectories(file);
    
  • api/src/main/java/ai/djl/util/ZipUtils.java+15 13 modified
    @@ -52,12 +52,10 @@ public static void unzip(InputStream is, Path dest) throws IOException {
             ZipEntry entry;
             Set<String> set = new HashSet<>();
             while ((entry = zis.getNextEntry()) != null) {
    -            String name = removeLeadingFileSeparator(entry.getName());
    -            if (name.contains("..")) {
    -                throw new IOException("Malicious zip entry: " + name);
    -            }
    -            set.add(name);
    -            Path file = dest.resolve(name).toAbsolutePath();
    +            String entryName = entry.getName();
    +            validateArchiveEntry(entry.getName(), dest);
    +            set.add(entryName);
    +            Path file = dest.resolve(entryName).toAbsolutePath();
                 if (entry.isDirectory()) {
                     Files.createDirectories(file);
                 } else {
    @@ -121,14 +119,18 @@ private static void addToZip(Path root, Path file, ZipOutputStream zos) throws I
             }
         }
     
    -    static String removeLeadingFileSeparator(String name) {
    -        int index = 0;
    -        for (; index < name.length(); index++) {
    -            if (name.charAt(index) != File.separatorChar) {
    -                break;
    -            }
    +    static void validateArchiveEntry(String name, Path destination) throws IOException {
    +        if (name.contains("..")) {
    +            throw new IOException("Invalid archive entry, contains traversal elements: " + name);
    +        }
    +        Path expectedOutputPath = destination.resolve(name).toAbsolutePath().normalize();
    +        if (!expectedOutputPath.startsWith(destination.normalize())) {
    +            throw new IOException(
    +                    "Bad archive entry "
    +                            + name
    +                            + ". Attempted write outside destination "
    +                            + destination);
             }
    -        return name.substring(index);
         }
     
         private static final class ValidationInputStream extends FilterInputStream {
    
  • api/src/test/java/ai/djl/util/ZipUtilsTest.java+31 6 modified
    @@ -47,15 +47,40 @@ public void testEmptyZipFile() throws IOException {
     
         @Test
         public void testOffendingTar() throws IOException {
    -        Path path = Paths.get("src/test/resources/offending.tar");
    +        String[] offendingTars =
    +                new String[] {
    +                    "src/test/resources/linux-created-offender-traversal-elements.tar",
    +                    "src/test/resources/windows-created-offender-traversal-elements.tar",
    +                    "src/test/resources/linux-created-offender-root.tar",
    +                    "src/test/resources/windows-created-offender-root.tar",
    +                };
             Path output = Paths.get("build/output");
    -        Path file = output.resolve("tmp/empty.txt");
    -        Utils.deleteQuietly(file);
             Files.createDirectories(output);
    -        try (InputStream is = Files.newInputStream(path)) {
    -            TarUtils.untar(is, output, false);
    +        for (String offendingTar : offendingTars) {
    +            Path tarPath = Paths.get(offendingTar);
    +            try (InputStream is = Files.newInputStream(tarPath)) {
    +                Assert.assertThrows(() -> TarUtils.untar(is, output, false));
    +            }
    +        }
    +    }
    +
    +    @Test
    +    public void testOffendingZip() throws IOException {
    +        String[] offendingTars =
    +                new String[] {
    +                    "src/test/resources/linux-created-offender-traversal-elements.zip",
    +                    "src/test/resources/windows-created-offender-traversal-elements.zip",
    +                    "src/test/resources/linux-created-offender-root.zip",
    +                    "src/test/resources/windows-created-offender-root.zip",
    +                };
    +        Path output = Paths.get("build/output");
    +        Files.createDirectories(output);
    +        for (String offendingTar : offendingTars) {
    +            Path tarPath = Paths.get(offendingTar);
    +            try (InputStream is = Files.newInputStream(tarPath)) {
    +                Assert.assertThrows(() -> ZipUtils.unzip(is, output));
    +            }
             }
    -        Assert.assertTrue(Files.exists(file));
         }
     
         @Test
    
  • api/src/test/resources/linux-created-offender-root.tar+0 0 added
  • api/src/test/resources/linux-created-offender-root.zip+0 0 added
  • api/src/test/resources/linux-created-offender-traversal-elements.tar+0 0 added
  • api/src/test/resources/linux-created-offender-traversal-elements.zip+0 0 added
  • api/src/test/resources/windows-created-offender-root.tar+0 0 added
  • api/src/test/resources/windows-created-offender-root.zip+0 0 added
  • api/src/test/resources/windows-created-offender-traversal-elements.tar+0 0 added
  • api/src/test/resources/windows-created-offender-traversal-elements.zip+0 0 added
  • integration/src/test/java/ai/djl/integration/IntegrationTests.java+1 1 modified
    @@ -38,7 +38,7 @@ public void runIntegrationTests() {
                 // TODO: windows CPU build is having OOM issue if 3 engines are loaded and running tests
                 // together
                 if (System.getProperty("os.name").startsWith("Win")) {
    -                engines.add("MXNet");
    +                engines.add("PyTorch");
                 } else if ("aarch64".equals(System.getProperty("os.arch"))) {
                     engines.add("PyTorch");
                 } else {
    

Vulnerability mechanics

Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

7

News mentions

0

No linked articles in our index yet.