apache/beam · error · IOException

Cannot unzip file containing an entry with ".." in the…

Error message

Cannot unzip file containing an entry with ".." in the name: 

What it means

ZipFiles.checkName guards against zip-slip path traversal: an entry whose name contains a '..' path element could escape targetDirectory when extracted. unzipFile rejects the whole archive with this IOException naming the offending entry.

Solutions

  1. Inspect and sanitize the zip: reject or rewrite entries containing '..' components before extraction
  2. Use a safe unzip helper that canonicalizes paths and validates they stay under targetDirectory
  3. Only unzip archives from trusted sources
  4. Quarantine the offending archive and alert on the attempt if it came from an untrusted uploader

Example fix

// before
ZipFiles.unzipFile(untrustedZip, target);
// after
try (ZipFile zf = new ZipFile(untrustedZip)) {
  for (ZipEntry e : Collections.list(zf.entries())) {
    if (Arrays.asList(new File(e.getName()).getPath().split("[\\/]")).contains("..")) {
      throw new IOException("unsafe entry: " + e.getName());
    }
  }
}
ZipFiles.unzipFile(untrustedZip, target);
Defensive patterns

Strategy: validation

Validate before calling

boolean hasUnsafeEntry(Path zip) throws IOException {
  try (ZipFile zf = new ZipFile(zip.toFile())) {
    return Collections.list(zf.entries()).stream().map(ZipEntry::getName)
        .anyMatch(n -> Arrays.asList(new File(n).getPath().split("[\\/]")).contains(".."));
  }
}

Try / catch

try {
  ZipFiles.unzipFile(zip, targetDir);
} catch (IOException e) {
  if (e.getMessage().contains("..\" in the name")) {
    // reject the archive as malicious/invalid
    throw new SecurityException("zip-slip attempt", e);
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling ZipFiles.unzipFile on a zip that contains an entry name with a literal '..' path component (e.g. '../../etc/passwd'), as opposed to harmless names like 'foo..bar'.

Common situations: Extracting untrusted zips downloaded from users or third parties; processing zips crafted for path-traversal attacks; CI jobs unpacking unvetted artifacts.

Understand the failure class

Background: Path traversal blocked: "path escapes the workspace" and "outside site root" errors when a path will not stay inside its allowed directory — this error's family across 26 libraries.

Related errors


AI-assisted analysis of apache/beam@12126d8942 (2026-09-13). Data as JSON: /api/errors/ea7e0f12c7afc6df. Report an issue: GitHub.

Appendix: source

Thrown at sdks/java/core/src/main/java/org/apache/beam/sdk/util/ZipFiles.java:162

  /**
   * Checks that the given entry name is legal for unzipping: if it contains ".." as a name element,
   * it could cause the entry to be unzipped outside the directory we're unzipping to.
   *
   * @throws IOException if the name is illegal
   */
  private static void checkName(String name) throws IOException {
    // First just check whether the entry name string contains "..".
    // This should weed out the vast majority of entries, which will not
    // contain "..".
    if (name.contains("..")) {
      // If the string does contain "..", break it down into its actual name
      // elements to ensure it actually contains ".." as a name, not just a
      // name like "foo..bar" or even "foo..", which should be fine.
      File file = new File(name);
      while (file != null) {
        if ("..".equals(file.getName())) {
          throw new IOException(
              "Cannot unzip file containing an entry with " + "\"..\" in the name: " + name);
        }
        file = file.getParentFile();
      }
    }
  }

  /**
   * Zips an entire directory specified by the path.
   *
   * @param sourceDirectory the directory to read from. This directory and all subdirectories will
   *     be added to the zip-file. The path within the zip file is relative to the directory given
   *     as parameter, not absolute.
   * @param zipFile the zip-file to write to.
   * @throws IOException the zipping failed, e.g. because the input was not readable.
   * @throws IllegalArgumentException sourceDirectory is not a directory, or zipFile already exists.
   */
  public static void zipDirectory(File sourceDirectory, File zipFile) throws IOException {

View on GitHub (pinned to 12126d8942)