quarkusio/quarkus · error · IOException

Bad ZIP entry: ${target}

Error message

Bad ZIP entry: ${target}

What it means

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.

Source

Thrown at core/deployment/src/main/java/io/quarkus/deployment/mutability/DevModeTask.java:166

                        }

                        @Override
                        public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException {
                            throw exc;
                        }

                        @Override
                        public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
                            return FileVisitResult.CONTINUE;
                        }
                    });
                } else {
                    try (ZipInputStream fs = new ZipInputStream(Files.newInputStream(p))) {
                        ZipEntry entry = fs.getNextEntry();
                        while (entry != null) {
                            Path target = moduleClasses.resolve(entry.getName()).normalize();
                            if (!target.startsWith(moduleClasses)) {
                                throw new IOException("Bad ZIP entry: " + target);
                            }
                            if (entry.getName().endsWith("/")) {
                                Files.createDirectories(target);
                            } else {
                                if (!Files.exists(target)) {
                                    // make sure the parent directories are created first
                                    // META-INF/MANIFEST.MF is often written first,
                                    // even before META-INF is written probably due to
                                    // https://bugs.openjdk.java.net/browse/JDK-8031748
                                    Files.createDirectories(target.getParent());
                                    try (OutputStream out = Files.newOutputStream(target)) {
                                        IoUtils.copy(out, fs);
                                    }
                                }
                            }

                            entry = fs.getNextEntry();
                        }

View on GitHub (pinned to e1c734241f)

Solutions

  1. Delete the stale/corrupt jar (typically under target/ or the dev-mode application directory) and rebuild with ./mvnw clean install -DskipTests.
  2. Inspect the jar contents (unzip -l) to find the entry with ../ or absolute-path components and identify which artifact produced it.
  3. Ensure no custom build step or shading plugin writes entries with path-traversal names.

Example fix

// inspect and rebuild
$ unzip -l target/quarkus-app/... | grep '\.\.'
$ ./mvnw clean install -DskipTests
# then restart dev mode
$ ./mvnw quarkus:dev
Defensive patterns

Strategy: validation

Validate before calling

try (ZipInputStream zis = new ZipInputStream(Files.newInputStream(jar))) {
    ZipEntry e;
    while ((e = zis.getNextEntry()) != null) {
        Path t = moduleClasses.resolve(e.getName()).normalize();
        if (!t.startsWith(moduleClasses)) throw new IllegalStateException("Unsafe entry: " + e.getName());
    }
}

Try / catch

try {
    extractDevModeClasses(...);
} catch (IOException e) {
    if (e.getMessage().startsWith("Bad ZIP entry")) {
        throw new IllegalStateException("Corrupt/malicious jar in dev-mode state; run mvn clean and rebuild", e);
    }
    throw e;
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05). Data as JSON: /api/errors/3214cafe4a1e0f4b. Report an issue: GitHub.