jenkinsci/jenkins · critical · IOException

Zip ${zipFile.getPath()} contains illegal file name that bre

Error message

Zip ${zipFile.getPath()} contains illegal file name that breaks out of the target directory: ${e.getName()}

What it means

Thrown by FilePath.unzip as a zip-slip guard: for each entry, Jenkins computes the target file's canonical path and requires it to start with the destination directory's canonical path. If an entry name like ../evil escapes the target, extraction aborts before writing outside the directory. This is a security control, not a convenience check.

Source

Thrown at core/src/main/java/hudson/FilePath.java:715

            // TODO why does this not simply use ZipInputStream?
            IOUtils.copy(in, tmpFile);
            unzip(dir, tmpFile);
        }
        finally {
            Files.delete(Util.fileToPath(tmpFile));
        }
    }

    private static void unzip(File dir, File zipFile) throws IOException {
        dir = dir.getAbsoluteFile();    // without absolutization, getParentFile below seems to fail

        try (ZipFile zip = new ZipFile(zipFile)) {
            Enumeration<ZipEntry> entries = zip.getEntries();
            while (entries.hasMoreElements()) {
                ZipEntry e = entries.nextElement();
                File f = new File(dir, e.getName());
                if (!f.getCanonicalFile().toPath().startsWith(dir.getCanonicalPath())) {
                    throw new IOException(
                        "Zip " + zipFile.getPath() + " contains illegal file name that breaks out of the target directory: " + e.getName());
                }
                if (e.isDirectory()) {
                    mkdirs(f);
                } else {
                    File p = f.getParentFile();
                    if (p != null) {
                        mkdirs(p);
                    }
                    try (InputStream input = zip.getInputStream(e)) {
                        IOUtils.copy(input, f);
                    }
                    try {
                        FilePath target = new FilePath(f);
                        int mode = e.getUnixMode();
                        if (mode != 0)    // Ant returns 0 if the archive doesn't record the access mode
                            target.chmod(mode);
                    } catch (InterruptedException | NoSuchFileException ex) {

View on GitHub (pinned to 2e228ff40b)

Solutions

  1. Do not unpack untrusted archives with FilePath.unzip; pre-validate or repackage with relative entry names.
  2. Inspect the archive entry names with `unzip -l` and remove/normalize any '..' or absolute paths.
  3. Repack the archive so all entries are relative and contained.
  4. If the source is trusted but sloppy, normalize entry names in a repackaging step before install.

Example fix

null
Defensive patterns

Strategy: validation

Validate before calling

static boolean isSafeArchive(File zipFile) throws IOException {
    Path base = zipFile.getParentFile().getCanonicalFile().toPath();
    try (ZipFile zf = new ZipFile(zipFile)) {
        Enumeration<? extends ZipEntry> en = zf.entries();
        while (en.hasMoreElements()) {
            Path target = new File(base.toFile(), en.nextElement().getName()).getCanonicalFile().toPath();
            if (!target.startsWith(base)) return false;
        }
    }
    return true;
}

Type guard

null

Try / catch

try {
    fp.unzipFrom(stream);
} catch (IOException e) {
    if (e.getMessage().contains("breaks out of the target directory")) {
        // reject the archive — do not attempt to sanitize path traversal
        throw new SecurityException("Refusing unsafe archive", e);
    }
    throw e;
}

Prevention

When it happens

Trigger: A zip/tar entry name contains '..' segments that resolve above the destination dir; an absolute entry path resolving outside dir; symbolic-link-heavy archive resolving outside; archive from an untrusted or compromised source.

Common situations: Unpacking a tool/archive downloaded from an untrusted URL via install/unpack; a vendor zip with malformed entry names; crafted archive in a supply-chain attack; archive produced by a tool that emits absolute paths.

Related errors


AI-assisted analysis of jenkinsci/jenkins@2e228ff40b (2026-08-14). Data as JSON: /api/errors/bd8d529af636d01c. Report an issue: GitHub.