alibaba/arthas · error · IOException

Bad zip entry: {currentEntry}

Error message

Bad zip entry: {currentEntry}

What it means

IOUtils.ungzip/unzip routine extracts each ZipEntry under a base directory newPath. Before writing, it checks isSubFile(newPath, destFile) — a path-traversal (zip-slip) guard ensuring the resolved destination stays inside newPath. If an entry resolves outside the base (e.g. ../ escapes or absolute paths), it throws IOException("Bad zip entry: <currentEntry>").

Source

Thrown at common/src/main/java/com/taobao/arthas/common/IOUtils.java:125

        ZipFile zip = null;
        try {
            int BUFFER = 1024 * 8;

            zip = new ZipFile(file);
            File newPath = new File(extractFolder);
            newPath.mkdirs();

            Enumeration<? extends ZipEntry> zipFileEntries = zip.entries();

            // Process each entry
            while (zipFileEntries.hasMoreElements()) {
                // grab a zip file entry
                ZipEntry entry = (ZipEntry) zipFileEntries.nextElement();
                String currentEntry = entry.getName();

                File destFile = new File(newPath, currentEntry);
                if (!isSubFile(newPath, destFile)) {
                    throw new IOException("Bad zip entry: " + currentEntry);
                }

                // destFile = new File(newPath, destFile.getName());
                File destinationParent = destFile.getParentFile();

                // create the parent directory structure if needed
                destinationParent.mkdirs();

                if (!entry.isDirectory()) {
                    BufferedInputStream is = null;
                    BufferedOutputStream dest = null;
                    try {
                        is = new BufferedInputStream(zip.getInputStream(entry));
                        int currentByte;
                        // establish buffer for writing file
                        byte data[] = new byte[BUFFER];

                        // write the current file to disk

View on GitHub (pinned to 21cf2e9ba5)

Solutions

  1. Only extract archives from trusted, checksum-verified sources.
  2. If you control packaging, ensure entry names are relative with no '..' segments.
  3. Catch IOException and abort the extraction, deleting partial output.
  4. Run extraction in a sandboxed/throwaway directory so escapes are contained.

Example fix

// before - blindly trust upstream archive
IOUtils.unzip(downloadedZip, targetDir);  // entry '../evil' -> throws Bad zip entry

// after - verify source + isolate
if (!checksumMatches(downloadedZip)) throw new IOException("untrusted archive");
File sandbox = Files.createTempDirectory("unzip").toFile();
try {
    IOUtils.unzip(downloadedZip, sandbox);
} catch (IOException e) {
    FileUtils.deleteQuietly(sandbox);
    throw e;
}
Defensive patterns

Strategy: validation

Validate before calling

File base = newPath.getCanonicalFile();
for (ZipEntry e : Collections.list(zip.entries())) {
    File dest = new File(newPath, e.getName()).getCanonicalFile();
    if (!dest.toPath().startsWith(base.toPath())) {
        throw new IOException("refusing zip-slip entry: " + e.getName());
    }
}

Type guard

static boolean allEntriesInside(ZipFile zip, File base) throws IOException {
    Path bp = base.getCanonicalFile().toPath();
    Enumeration<? extends ZipEntry> en = zip.entries();
    while (en.hasMoreElements()) {
        Path dp = new File(base, en.nextElement().getName()).getCanonicalFile().toPath();
        if (!dp.startsWith(bp)) return false;
    }
    return true;
}

Try / catch

try {
    IOUtils.unzip(zip, targetDir);
} catch (IOException e) {
    if (e.getMessage().startsWith("Bad zip entry")) {
        FileUtils.deleteQuietly(targetDir); // discard partial extraction
        throw new SecurityException("rejected malicious archive", e);
    }
    throw e;
}

Prevention

When it happens

Trigger: Extracting a maliciously or accidentally crafted archive whose entry names contain '..' segments or absolute paths that would escape the target directory (classic zip-slip).

Common situations: Downloading an Arthas distribution/archive from an untrusted or tampered source; a re-packaged archive with entry names like ../../etc/passwd; an archiver that emitted absolute entry names.

Related errors


AI-assisted analysis of alibaba/arthas@21cf2e9ba5 (2026-08-14). Data as JSON: /api/errors/c7745ea48385393c. Report an issue: GitHub.