MuntashirAkon/AppManager · error · IOException
Zip slip vulnerability detected!\nExpected dest: " + new Fil
Error message
Zip slip vulnerability detected!\nExpected dest: " + new File(realDestPath, entry.getName()) + "\nActual path: " + (filename != null ? new File(realDestPath, filename) : realDestPath)
What it means
IOException thrown by AndroidBackupExtractor while parsing an Android 'ab' backup TAR stream: an entry whose normalized path is null or starts with '../' would extract outside the destination directory, so the extractor aborts before creating any file. This is the early zip-slip defense against path traversal in malicious backup archives.
Source
Thrown at app/src/main/java/io/github/muntashirakon/AppManager/backup/adb/AndroidBackupExtractor.java:76
public AndroidBackupExtractor(@NonNull Path abFile, @NonNull Path temporaryDir, @NonNull String packageName) throws IOException {
mWorkingDir = temporaryDir;
String relativeDirInAb = Constants.APPS_PREFIX + packageName + File.separator;
String abFilename = Paths.trimPathExtension(abFile.getName());
Path tarFile = temporaryDir.createNewFile(abFilename + ".tar", null);
mFilesToBeDeleted.add(tarFile);
Path dest = temporaryDir.createNewDirectory(abFilename);
mFilesToBeDeleted.add(dest);
toTar(abFile, tarFile, null);
try (InputStream fis = tarFile.openInputStream();
TarArchiveInputStream tis = new TarArchiveInputStream(fis)) {
String realDestPath = dest.getRealFilePath();
int relDirSize = relativeDirInAb.length();
TarArchiveEntry entry;
while ((entry = tis.getNextTarEntry()) != null) {
String filename = Paths.normalize(entry.getName());
// Early zip slip vulnerability check to avoid creating any files at all
if (filename == null || filename.startsWith("../")) {
throw new IOException("Zip slip vulnerability detected!" +
"\nExpected dest: " + new File(realDestPath, entry.getName()) +
"\nActual path: " + (filename != null ? new File(realDestPath, filename) : realDestPath));
}
if (!filename.startsWith(relativeDirInAb)) {
throw new IOException("Unsupported file in AB: " + filename);
}
// Remove apps/{packageName}/ part
filename = filename.substring(relDirSize);
Path file;
if (entry.isDirectory()) {
file = dest.createDirectoriesIfRequired(filename);
} else file = dest.createNewArbitraryFile(filename, null);
// Check if the given entry is a link.
if (entry.isSymbolicLink() && file.getFilePath() != null) {
String linkName = entry.getLinkName();
file.delete();
file.createNewSymbolicLink(linkName);
} else {View on GitHub (pinned to 0152f468fc)
Solutions
- Do not use the backup archive — it is malicious or corrupt; obtain a clean backup
- Re-create the backup with App Manager or adb backup so entry names are relative and sanitized
- Inspect archive entry names for '../' before extraction with a separate tool
- Ensure extraction destination is dedicated and readable, then re-run with a trusted archive
Example fix
// before (caller passes an untrusted .ab straight to extraction)
extractor.extract(new File("untrusted.ab"), destDir);
// after (pre-screen entry names)
for (String name : listTarEntryNames(backupFile)) {
if (name == null || Paths.normalize(name) == null || Paths.normalize(name).startsWith("../")) {
throw new IOException("Rejecting archive: unsafe entry " + name);
}
}
extractor.extract(new File("untrusted.ab"), destDir); Defensive patterns
Strategy: validation
Validate before calling
boolean isSafe(String entryName) {
String norm = Paths.normalize(entryName);
return norm != null && !norm.startsWith("../");
} Type guard
// Java has no runtime type narrowing; use a predicate
java.util.function.Predicate<String> safeEntry =
name -> Paths.normalize(name) != null && !Paths.normalize(name).startsWith("../"); Try / catch
try {
extractor.extract();
} catch (IOException e) {
if (e.getMessage().contains("Zip slip")) {
Log.e(TAG, "Refusing malicious backup archive", e);
deletePartialOutput(destDir);
} else throw e;
} Prevention
- Only restore backups from trusted sources
- Extract into a fresh dedicated directory
- Pre-scan TAR entry names for traversal sequences
- Keep security checks in place; never bypass them for convenience
When it happens
Trigger: Feeding the extractor a crafted or corrupt .ab file where a TAR entry name contains '../' (or normalizes to nothing), causing new File(realDestPath, entry.getName()) to escape realDestPath.
Common situations: Restoring an untrusted/shared backup file; archives produced by third-party tools that don't sanitize entry names; tampered backups intended to overwrite files elsewhere on the filesystem.
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
- Zip slip vulnerability detected! Expected dest: ${new File(r
- Zip slip vulnerability detected! Expected dest: ${new File(r
- Zip slip vulnerability detected!\nExpected dest: " + new Fil
- Could not create directories in the parent directory.
- Error! Invalid characters in arguments.\n
AI-assisted analysis of MuntashirAkon/AppManager@0152f468fc (2026-09-12).
Data as JSON: /api/errors/f58436345c0c9107.
Report an issue: GitHub.