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

  1. Reject and quarantine the tar; log entry.getName() — this is a traversal attempt, not a transient fault
  2. Rebuild the tar with relative, contained paths and verify checksums before deployment
  3. Pre-scan with TarArchiveInputStream and reject entries whose resolved normalize()d path leaves outputDir
  4. 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

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


AI-assisted analysis of apache/hadoop@2add963021 (2026-08-22). Data as JSON: /api/errors/d870bdcacf294650. Report an issue: GitHub.