{"record":{"id":"b77d529a67a57140","repo":"apache/flink","slug":"expand-entry-getname-would-create-a-file-outsi","errorCode":null,"errorMessage":"Expand {entry.getName()} would create a file outside of {targetPath}","messagePattern":"Expand (.+?) would create a file outside of (.+?)","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"critical","filePath":"flink-core/src/main/java/org/apache/flink/util/CompressionUtils.java","lineNumber":226,"sourceCode":"     * attacks.\n     */\n    private static String makeSecureShellPath(String filePath) {\n        return filePath.replace(\"'\", \"'\\\\''\");\n    }\n\n    public static void extractZipFileWithPermissions(String zipFilePath, String targetPath)\n            throws IOException {\n        try (ZipFile zipFile = new ZipFile(zipFilePath)) {\n            Enumeration<ZipArchiveEntry> entries = zipFile.getEntries();\n            boolean isUnix = isUnix();\n            ByteArrayOutputStream baos = new ByteArrayOutputStream();\n            String canonicalTargetPath = new File(targetPath).getCanonicalPath() + File.separator;\n\n            while (entries.hasMoreElements()) {\n                ZipArchiveEntry entry = entries.nextElement();\n                File outputFile = new File(canonicalTargetPath, entry.getName());\n                if (!outputFile.getCanonicalPath().startsWith(canonicalTargetPath)) {\n                    throw new IOException(\n                            \"Expand \"\n                                    + entry.getName()\n                                    + \" would create a file outside of \"\n                                    + targetPath);\n                }\n\n                if (entry.isDirectory()) {\n                    if (!outputFile.exists()) {\n                        if (!outputFile.mkdirs()) {\n                            throw new IOException(\n                                    \"Create dir: \" + outputFile.getAbsolutePath() + \" failed!\");\n                        }\n                    }\n                } else {\n                    File parentDir = outputFile.getParentFile();\n                    if (!parentDir.exists()) {\n                        if (!parentDir.mkdirs()) {\n                            throw new IOException(","sourceCodeStart":208,"sourceCodeEnd":244,"githubUrl":"https://github.com/apache/flink/blob/2f3c205e9266cb30240eb7f4fdab15cad629a70f/flink-core/src/main/java/org/apache/flink/util/CompressionUtils.java#L208-L244","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","solutions":["Inspect the offending entry: `unzip -l archive.zip` and look for absolute or `../` prefixed names","Rebuild the zip from trusted content with relative entry names","Treat the archive as untrusted input and reject it; never relax the check"],"exampleFix":"// before\nCompressionUtils.extractZipFileWithPermissions(untrustedZip, target);\n\n// after: validate entries first\ntry (ZipFile z = new ZipFile(untrustedZip)) {\n    z.getEntries().asIterator().forEachRemaining(e -> {\n        if (e.getName().startsWith(\"/\") || e.getName().contains(\"..\"))\n            throw new IOException(\"Illegal entry \" + e.getName());\n    });\n}\nCompressionUtils.extractZipFileWithPermissions(untrustedZip, target);","handlingStrategy":"validation","validationCode":"try (ZipFile z = new ZipFile(zipPath)) {\n    Enumeration<ZipArchiveEntry> en = z.getEntries();\n    while (en.hasMoreElements()) {\n        String n = en.nextElement().getName();\n        if (n.startsWith(\"/\") || n.contains(\"..\")) throw new IOException(\"Unsafe zip entry \" + n);\n    }\n}","typeGuard":null,"tryCatchPattern":"catch (IOException) and permanently reject the archive; log the entry name for audit — traversal is a security signal, not a transient error.","preventionTips":["Treat archives from users/network as untrusted; validate entries before extraction","Verify signatures/checksums of downloaded zips and jars before unpacking"],"tags":["flink-core","compression","security","zip-slip","path-traversal","zip"],"backgroundTag":null,"analyzedSha":"2f3c205e9266cb30240eb7f4fdab15cad629a70f","analyzedAt":"2026-08-14T08:48:24.518Z","schemaVersion":2},"datasetVersion":"2026-08-14T10:17:34.591Z"}