apache/hadoop · error · IOException
expanding " + entry.getName() + " would create file outside
Error message
expanding " + entry.getName() + " would create file outside of " + unzipDir
What it means
unZip(File inFile, File unzipDir) (the ZipFile-based variant reading from a file rather than a stream) throws IOException("expanding <entry> would create file outside of <unzipDir>") when an entry's canonical path escapes the target directory. Same Zip Slip guard as the stream variant: entry names with '../' segments or absolute paths are rejected before any bytes are written. The abort happens lazily, mid-iteration, so earlier entries may already be extracted.
Source
Thrown at hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/FileUtil.java:841
* @param inFile The zip file as input
* @param unzipDir The unzip directory where to unzip the zip file.
* @throws IOException An I/O exception has occurred
*/
public static void unZip(File inFile, File unzipDir) throws IOException {
Enumeration<? extends ZipArchiveEntry> entries;
ZipFile zipFile = new ZipFile(inFile);
try {
entries = zipFile.getEntries();
String targetDirPath = unzipDir.getCanonicalPath() + File.separator;
while (entries.hasMoreElements()) {
ZipArchiveEntry entry = entries.nextElement();
if (!entry.isDirectory()) {
InputStream in = zipFile.getInputStream(entry);
try {
File file = new File(unzipDir, entry.getName());
if (!file.getCanonicalPath().startsWith(targetDirPath)) {
throw new IOException("expanding " + entry.getName()
+ " would create file outside of " + unzipDir);
}
if (!file.getParentFile().mkdirs()) {
if (!file.getParentFile().isDirectory()) {
throw new IOException("Mkdirs failed to create " +
file.getParentFile().toString());
}
}
OutputStream out = Files.newOutputStream(file.toPath());
try {
byte[] buffer = new byte[8192];
int i;
while ((i = in.read(buffer)) != -1) {
out.write(buffer, 0, i);
}
} finally {
out.close();
}View on GitHub (pinned to 2add963021)
Solutions
- Quarantine and reject the archive; capture entry.getName() in logs for triage — this is attempted path traversal, treat it as a security event
- Rebuild or re-download the artifact from a trusted source and verify a checksum/signature before unzipping
- Pre-validate entries (canonical-path containment check) before calling unZip so rejection is atomic
- Extract as an unprivileged user into a scratch dir to limit damage from partially-extracted content
Example fix
// before
FileUtil.unZip(new File("plugin.zip"), pluginDir); // aborts mid-archive
// after: fail fast on the first bad entry, before anything is written
Path root = pluginDir.getCanonicalFile().toPath();
try (ZipFile zf = new ZipFile(new File("plugin.zip"))) {
Enumeration<ZipArchiveEntry> en = zf.getEntries();
while (en.hasMoreElements()) {
Path resolved = root.resolve(en.nextElement().getName()).normalize();
if (!resolved.startsWith(root)) {
throw new IOException("Unsafe zip entry rejected");
}
}
}
FileUtil.unZip(new File("plugin.zip"), pluginDir); Defensive patterns
Strategy: try-catch
Validate before calling
Path root = unzipDir.getCanonicalFile().toPath();
try (ZipFile zf = new ZipFile(inFile)) {
Enumeration<ZipArchiveEntry> en = zf.getEntries();
while (en.hasMoreElements()) {
if (!root.resolve(en.nextElement().getName()).normalize().startsWith(root)) {
throw new SecurityException("Unsafe zip entry");
}
}
} Try / catch
try {
FileUtil.unZip(inFile, unzipDir);
} catch (IOException e) {
if (e.getMessage() != null && e.getMessage().contains("outside of")) {
rejectArchive(inFile); // security event: traversal attempt
} else throw e;
} Prevention
- Verify checksums/signatures of downloaded zips before extraction
- Treat 'would create file outside of' as a security signal, never sanitize and continue
- Run extraction unprivileged into disposable directories
When it happens
Trigger: unZip(new File("bundle.zip"), unzipDir) where bundle.zip contains entries like '../../../sbin/install' or absolute paths; hostile or corrupted third-party archives fed to the file-based API.
Common situations: Downloading plugin/connector zips and extracting on the node; accepting user-supplied archives; mirrored artifacts tampered in transit or by a compromised upstream.
Related errors
- expanding " + entry.getName() + " would create file outside
- expanding " + entry.getName() + " would create entry outside
- expanding {} would create file outside of {}
- Mkdirs failed to create " + parent.getAbsolutePath()
- Mkdirs failed to create " + file.getParentFile().toString()
AI-assisted analysis of apache/hadoop@2add963021 (2026-08-22).
Data as JSON: /api/errors/d1651e72f4e509c4.
Report an issue: GitHub.