apache/flink · critical · IOException

Expand {entry.getName()} would create a file outside of {tar

Error message

Expand {entry.getName()} would create a file outside of {targetPath}

What it means

Zip-slip protection in extractZipFileWithPermissions: each zip entry's canonical output path must start with the canonical target directory. A zip entry using absolute paths or `../` segments that resolves outside the target is rejected. This is the zip counterpart of the tar traversal guard.

Source

Thrown at flink-core/src/main/java/org/apache/flink/util/CompressionUtils.java:226

     * attacks.
     */
    private static String makeSecureShellPath(String filePath) {
        return filePath.replace("'", "'\\''");
    }

    public static void extractZipFileWithPermissions(String zipFilePath, String targetPath)
            throws IOException {
        try (ZipFile zipFile = new ZipFile(zipFilePath)) {
            Enumeration<ZipArchiveEntry> entries = zipFile.getEntries();
            boolean isUnix = isUnix();
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            String canonicalTargetPath = new File(targetPath).getCanonicalPath() + File.separator;

            while (entries.hasMoreElements()) {
                ZipArchiveEntry entry = entries.nextElement();
                File outputFile = new File(canonicalTargetPath, entry.getName());
                if (!outputFile.getCanonicalPath().startsWith(canonicalTargetPath)) {
                    throw new IOException(
                            "Expand "
                                    + entry.getName()
                                    + " would create a file outside of "
                                    + targetPath);
                }

                if (entry.isDirectory()) {
                    if (!outputFile.exists()) {
                        if (!outputFile.mkdirs()) {
                            throw new IOException(
                                    "Create dir: " + outputFile.getAbsolutePath() + " failed!");
                        }
                    }
                } else {
                    File parentDir = outputFile.getParentFile();
                    if (!parentDir.exists()) {
                        if (!parentDir.mkdirs()) {
                            throw new IOException(

View on GitHub (pinned to 2f3c205e92)

Solutions

  1. Inspect the offending entry: `unzip -l archive.zip` and look for absolute or `../` prefixed names
  2. Rebuild the zip from trusted content with relative entry names
  3. Treat the archive as untrusted input and reject it; never relax the check

Example fix

// before
CompressionUtils.extractZipFileWithPermissions(untrustedZip, target);

// after: validate entries first
try (ZipFile z = new ZipFile(untrustedZip)) {
    z.getEntries().asIterator().forEachRemaining(e -> {
        if (e.getName().startsWith("/") || e.getName().contains(".."))
            throw new IOException("Illegal entry " + e.getName());
    });
}
CompressionUtils.extractZipFileWithPermissions(untrustedZip, target);
Defensive patterns

Strategy: validation

Validate before calling

try (ZipFile z = new ZipFile(zipPath)) {
    Enumeration<ZipArchiveEntry> en = z.getEntries();
    while (en.hasMoreElements()) {
        String n = en.nextElement().getName();
        if (n.startsWith("/") || n.contains("..")) throw new IOException("Unsafe zip entry " + n);
    }
}

Try / catch

catch (IOException) and permanently reject the archive; log the entry name for audit — traversal is a security signal, not a transient error.

Prevention

When it happens

Trigger: Extracting a zip/jar containing entries such as `../evil.class` or `/etc/evil` — common in maliciously crafted archives or in zips produced by tools that store absolute member names. Reached when the file suffix is not tar-ish (zip/jar/unknown suffix fallback).

Common situations: Extracting untrusted user JARs or plugin bundles; zips created with absolute paths (some archive tools do this); penetration testing or an actual supply-chain attempt.

Related errors


AI-assisted analysis of apache/flink@2f3c205e92 (2026-08-14). Data as JSON: /api/errors/b77d529a67a57140. Report an issue: GitHub.