apache/hadoop · error · IOException
expanding " + entry.getName() + " would create entry outside
Error message
expanding " + entry.getName() + " would create entry outside of " + outputDir
What it means
unpackEntries, the engine behind unTarUsingJava, resolves each tar entry to File(outputDir, entry.getName()) and throws IOException("expanding <entry> would create entry outside of <outputDir>") when its canonical path does not start with outputDir's canonical path + separator. This is the tar equivalent of the Zip Slip guard: entry names with '../' or absolute components are rejected. It fires during extraction, after earlier entries may already be on disk.
Source
Thrown at hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/FileUtil.java:1135
}
inputStream = new BufferedInputStream(inputStream);
tis = new TarArchiveInputStream(inputStream);
for (TarArchiveEntry entry = tis.getNextTarEntry(); entry != null;) {
unpackEntries(tis, entry, untarDir);
entry = tis.getNextTarEntry();
}
} finally {
IOUtils.cleanupWithLogger(LOG, tis, inputStream);
}
}
private static void unpackEntries(TarArchiveInputStream tis,
TarArchiveEntry entry, File outputDir) throws IOException {
String targetDirPath = outputDir.getCanonicalPath() + File.separator;
File outputFile = new File(outputDir, entry.getName());
if (!outputFile.getCanonicalPath().startsWith(targetDirPath)) {
throw new IOException("expanding " + entry.getName()
+ " would create entry outside of " + outputDir);
}
if (entry.isSymbolicLink() || entry.isLink()) {
String canonicalTargetPath = getCanonicalPath(entry.getLinkName(), outputDir);
if (!canonicalTargetPath.startsWith(targetDirPath)) {
throw new IOException(
"expanding " + entry.getName() + " would create entry outside of " + outputDir);
}
}
if (entry.isDirectory()) {
File subDir = new File(outputDir, entry.getName());
if (!subDir.mkdirs() && !subDir.isDirectory()) {
throw new IOException("Mkdirs failed to create tar internal dir "
+ outputDir);
}
View on GitHub (pinned to 2add963021)
Solutions
- Reject and quarantine the tar; log entry.getName() — this is a traversal attempt, not a transient fault
- Rebuild the tar with relative, contained paths and verify checksums before deployment
- Pre-scan with TarArchiveInputStream and reject entries whose resolved normalize()d path leaves outputDir
- Extract unprivileged into a scratch directory to limit partial-extraction damage
Example fix
// before
FileUtil.unTar(in, untarDir, gzipped); // Java path aborts on traversal entry
// after: pre-validate names against the canonical root
Path root = untarDir.getCanonicalFile().toPath();
try (TarArchiveInputStream t =
new TarArchiveInputStream(
gzipped ? new GzipCompressorInputStream(in) : in)) {
for (TarArchiveEntry e = t.getNextTarEntry(); e != null;
e = t.getNextTarEntry()) {
if (!root.resolve(e.getName()).normalize().startsWith(root)) {
throw new IOException("Unsafe tar entry: " + e.getName());
}
}
} Defensive patterns
Strategy: try-catch
Validate before calling
Path root = untarDir.getCanonicalFile().toPath();
try (TarArchiveInputStream t = new TarArchiveInputStream(in)) {
for (TarArchiveEntry e = t.getNextTarEntry(); e != null; e = t.getNextTarEntry()) {
if (!root.resolve(e.getName()).normalize().startsWith(root)) {
throw new SecurityException("Tar slip entry: " + e.getName());
}
}
} Try / catch
try {
FileUtil.unTar(in, dir, gzipped);
} catch (IOException e) {
if (e.getMessage() != null && e.getMessage().contains("outside of")) {
quarantine(tarFile); // traversal attempt in entry name
} else throw e;
} Prevention
- Only untar trusted, checksum-verified artifacts
- Pre-scan names so rejection happens before any bytes are written
- Extract into disposable low-privilege scratch dirs
When it happens
Trigger: unTarUsingJava (Windows path, or fallback) on a tar containing entries like '../../bin/sh' or '/etc/ld.so.preload'; hostile tars from untrusted sources; corrupt archives with malformed name fields.
Common situations: Extracting third-party native bundles; CVE-style tar traversal payloads; test fixtures built with weird tools.
Related errors
- expanding " + entry.getName() + " would create file outside
- expanding " + entry.getName() + " would create file outside
- expanding {} would create file outside of {}
- Error executing command. %s Process exited with exit code %d
- Mkdirs failed to create " + untarDir
AI-assisted analysis of apache/hadoop@2add963021 (2026-08-22).
Data as JSON: /api/errors/d870bdcacf294650.
Report an issue: GitHub.