{"record":{"id":"3214cafe4a1e0f4b","repo":"quarkusio/quarkus","slug":"bad-zip-entry-target","errorCode":null,"errorMessage":"Bad ZIP entry: ${target}","messagePattern":"Bad ZIP entry: (.+?)","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"error","filePath":"core/deployment/src/main/java/io/quarkus/deployment/mutability/DevModeTask.java","lineNumber":166,"sourceCode":"                        }\n\n                        @Override\n                        public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException {\n                            throw exc;\n                        }\n\n                        @Override\n                        public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {\n                            return FileVisitResult.CONTINUE;\n                        }\n                    });\n                } else {\n                    try (ZipInputStream fs = new ZipInputStream(Files.newInputStream(p))) {\n                        ZipEntry entry = fs.getNextEntry();\n                        while (entry != null) {\n                            Path target = moduleClasses.resolve(entry.getName()).normalize();\n                            if (!target.startsWith(moduleClasses)) {\n                                throw new IOException(\"Bad ZIP entry: \" + target);\n                            }\n                            if (entry.getName().endsWith(\"/\")) {\n                                Files.createDirectories(target);\n                            } else {\n                                if (!Files.exists(target)) {\n                                    // make sure the parent directories are created first\n                                    // META-INF/MANIFEST.MF is often written first,\n                                    // even before META-INF is written probably due to\n                                    // https://bugs.openjdk.java.net/browse/JDK-8031748\n                                    Files.createDirectories(target.getParent());\n                                    try (OutputStream out = Files.newOutputStream(target)) {\n                                        IoUtils.copy(out, fs);\n                                    }\n                                }\n                            }\n\n                            entry = fs.getNextEntry();\n                        }","sourceCodeStart":148,"sourceCodeEnd":184,"githubUrl":"https://github.com/quarkusio/quarkus/blob/e1c734241f34c7919086ceb4c9262b4a58f6de44/core/deployment/src/main/java/io/quarkus/deployment/mutability/DevModeTask.java#L148-L184","documentation":"DevModeTask.extractDevModeClasses throws this IOException when extracting entries from an application jar in dev mode would write outside the target module classes directory. After resolving and normalizing the ZIP entry name against moduleClasses, any entry whose normalized path does not start with moduleClasses is treated as a path traversal (zip-slip) attack and rejected.","triggerScenarios":"Starting dev mode with an application jar (in the quarkus application dev-mode dir) containing a ZIP entry with a name like ../../foo.class or an absolute path; extraction resolves outside moduleClasses and throws.","commonSituations":"A corrupted or maliciously crafted jar in local dev-mode state; stale jars from a previous build replaced by artifacts with odd entry names; running dev mode against jars produced by a broken build pipeline.","solutions":["Delete the stale/corrupt jar (typically under target/ or the dev-mode application directory) and rebuild with ./mvnw clean install -DskipTests.","Inspect the jar contents (unzip -l) to find the entry with ../ or absolute-path components and identify which artifact produced it.","Ensure no custom build step or shading plugin writes entries with path-traversal names."],"exampleFix":"// inspect and rebuild\n$ unzip -l target/quarkus-app/... | grep '\\.\\.'\n$ ./mvnw clean install -DskipTests\n# then restart dev mode\n$ ./mvnw quarkus:dev","handlingStrategy":"validation","validationCode":"try (ZipInputStream zis = new ZipInputStream(Files.newInputStream(jar))) {\n    ZipEntry e;\n    while ((e = zis.getNextEntry()) != null) {\n        Path t = moduleClasses.resolve(e.getName()).normalize();\n        if (!t.startsWith(moduleClasses)) throw new IllegalStateException(\"Unsafe entry: \" + e.getName());\n    }\n}","typeGuard":null,"tryCatchPattern":"try {\n    extractDevModeClasses(...);\n} catch (IOException e) {\n    if (e.getMessage().startsWith(\"Bad ZIP entry\")) {\n        throw new IllegalStateException(\"Corrupt/malicious jar in dev-mode state; run mvn clean and rebuild\", e);\n    }\n    throw e;\n}","preventionTips":["Run mvn clean after suspicious build failures to remove stale jars.","Scan dependency jars for entries containing ../ or absolute paths.","Keep the build pipeline and shading configuration from writing unusual entry names."],"tags":["quarkus","dev-mode","zip","zip-slip","path-traversal"],"backgroundTag":"zip-slip-path-traversal","analyzedSha":"e1c734241f34c7919086ceb4c9262b4a58f6de44","analyzedAt":"2026-09-05T17:01:29.979Z","contentChangedAt":"2026-09-05T17:01:29.979Z","schemaVersion":2},"datasetVersion":"2026-09-12T22:17:10.623Z"}