Tencent/matrix · error · IllegalStateException
extractZipEntry entry
Error message
extractZipEntry entry ${targetEntry.getName()} failed! What it means
StreamUtil.extractZipEntry extracts a single zip entry to an output file, but first calls preventZipSlip to verify the entry name doesn't escape the output directory (zip-slip path traversal). If the guard trips, it throws IllegalStateException('extractZipEntry entry <name> failed!'). The library deliberately refuses entries whose resolved path lies outside the target directory.
Solutions
- Inspect the offending entry name and sanitize it (strip leading '/', resolve '..') before extraction.
- Only extract archives from trusted sources; reject or quarantine suspicious entries.
- Extract to a fresh empty directory so entry names can't collide with existing files outside the target.
- If you control archive creation, ensure entry names are plain relative paths.
Example fix
// before
StreamUtil.extractZipEntry(zipFile, entry, new File("/data/out")); // entry = "../../evil.so"
// after
String safeName = entry.getName().replace("\\", "/").replaceAll("(^|/)\\.\\.(/|$)", "");
ZipEntry safe = new ZipEntry(safeName);
StreamUtil.extractZipEntry(zipFile, safe, new File("/data/out")); Defensive patterns
Strategy: validation
Validate before calling
String name = entry.getName().replace('\\', '/');
File outDir = output.getCanonicalFile();
File target = new File(outDir, name).getCanonicalFile();
if (!target.getPath().startsWith(outDir.getPath() + File.separator)) {
throw new SecurityException("zip-slip entry rejected: " + name);
} Type guard
static boolean isSafeEntryName(String name) {
return !name.startsWith("/") && !name.contains("..") && !name.contains("\\");
} Try / catch
try {
StreamUtil.extractZipEntry(zipFile, entry, output);
} catch (IllegalStateException e) {
Log.w(TAG, "Rejected unsafe zip entry", e);
} Prevention
- Only extract archives from trusted sources
- Sanitize entry names to relative paths without '..' or absolute prefixes
- Extract into a fresh empty directory
When it happens
Trigger: Extracting a zip entry whose name contains '..' segments, an absolute path, or a name that resolves outside the given output File's directory — typically from a crafted or third-party hprof/zip file.
Common situations: Processing untrusted or externally supplied archive files; zips created on Windows with backslash separators mis-resolved as separators; renamed entries in repacked archives pointing to parent directories.
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 Tencent/matrix@3b8293bd65 (2026-09-08).
Data as JSON: /api/errors/f8090b3b0af45bed.
Report an issue: GitHub.
Appendix: source
Thrown at matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-common/src/main/java/com/tencent/matrix/resource/common/utils/StreamUtil.java:68
}
public static boolean preventZipSlip(java.io.File output, String zipEntryName) {
try {
if (zipEntryName.contains("..") && new File(output, zipEntryName).getCanonicalPath().startsWith(output.getCanonicalPath() + File.separator)) {
return true;
}
} catch (IOException e) {
e.printStackTrace();
return true;
}
return false;
}
public static void extractZipEntry(ZipFile zipFile, ZipEntry targetEntry, File output) throws IOException {
if (preventZipSlip(output, targetEntry.getName())) {
throw new IllegalStateException("extractZipEntry entry " + targetEntry.getName() + " failed!");
}
InputStream is = null;
OutputStream os = null;
try {
is = new BufferedInputStream(zipFile.getInputStream(targetEntry));
os = new BufferedOutputStream(new FileOutputStream(output));
final byte[] buffer = new byte[4096];
int bytesRead = 0;
while ((bytesRead = is.read(buffer)) > 0) {
os.write(buffer, 0, bytesRead);
}
} finally {
closeQuietly(os);
closeQuietly(is);
}
}
View on GitHub (pinned to 3b8293bd65)