{"record":{"id":"f58436345c0c9107","repo":"MuntashirAkon/AppManager","slug":"zip-slip-vulnerability-detected-nexpected-dest-new-file","errorCode":null,"errorMessage":"Zip slip vulnerability detected!\\nExpected dest: \" + new File(realDestPath, entry.getName()) + \"\\nActual path: \" + (filename != null ? new File(realDestPath, filename) : realDestPath)","messagePattern":"Zip slip vulnerability detected!\\\\nExpected dest: \" \\+ new File\\(realDestPath, entry\\.getName\\(\\)\\) \\+ \"\\\\nActual path: \" \\+ \\(filename != null \\? new File\\(realDestPath, filename\\) : realDestPath\\)","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"error","filePath":"app/src/main/java/io/github/muntashirakon/AppManager/backup/adb/AndroidBackupExtractor.java","lineNumber":76,"sourceCode":"    public AndroidBackupExtractor(@NonNull Path abFile, @NonNull Path temporaryDir, @NonNull String packageName) throws IOException {\n        mWorkingDir = temporaryDir;\n        String relativeDirInAb = Constants.APPS_PREFIX + packageName + File.separator;\n        String abFilename = Paths.trimPathExtension(abFile.getName());\n        Path tarFile = temporaryDir.createNewFile(abFilename + \".tar\", null);\n        mFilesToBeDeleted.add(tarFile);\n        Path dest = temporaryDir.createNewDirectory(abFilename);\n        mFilesToBeDeleted.add(dest);\n        toTar(abFile, tarFile, null);\n        try (InputStream fis = tarFile.openInputStream();\n             TarArchiveInputStream tis = new TarArchiveInputStream(fis)) {\n            String realDestPath = dest.getRealFilePath();\n            int relDirSize = relativeDirInAb.length();\n            TarArchiveEntry entry;\n            while ((entry = tis.getNextTarEntry()) != null) {\n                String filename = Paths.normalize(entry.getName());\n                // Early zip slip vulnerability check to avoid creating any files at all\n                if (filename == null || filename.startsWith(\"../\")) {\n                    throw new IOException(\"Zip slip vulnerability detected!\" +\n                            \"\\nExpected dest: \" + new File(realDestPath, entry.getName()) +\n                            \"\\nActual path: \" + (filename != null ? new File(realDestPath, filename) : realDestPath));\n                }\n                if (!filename.startsWith(relativeDirInAb)) {\n                    throw new IOException(\"Unsupported file in AB: \" + filename);\n                }\n                // Remove apps/{packageName}/ part\n                filename = filename.substring(relDirSize);\n                Path file;\n                if (entry.isDirectory()) {\n                    file = dest.createDirectoriesIfRequired(filename);\n                } else file = dest.createNewArbitraryFile(filename, null);\n                // Check if the given entry is a link.\n                if (entry.isSymbolicLink() && file.getFilePath() != null) {\n                    String linkName = entry.getLinkName();\n                    file.delete();\n                    file.createNewSymbolicLink(linkName);\n                } else {","sourceCodeStart":58,"sourceCodeEnd":94,"githubUrl":"https://github.com/MuntashirAkon/AppManager/blob/0152f468fc9463ee02dc2ca83f6fe4989a2c4ca5/app/src/main/java/io/github/muntashirakon/AppManager/backup/adb/AndroidBackupExtractor.java#L58-L94","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before (caller passes an untrusted .ab straight to extraction)\nextractor.extract(new File(\"untrusted.ab\"), destDir);\n// after (pre-screen entry names)\nfor (String name : listTarEntryNames(backupFile)) {\n    if (name == null || Paths.normalize(name) == null || Paths.normalize(name).startsWith(\"../\")) {\n        throw new IOException(\"Rejecting archive: unsafe entry \" + name);\n    }\n}\nextractor.extract(new File(\"untrusted.ab\"), destDir);","handlingStrategy":"validation","validationCode":"boolean isSafe(String entryName) {\n    String norm = Paths.normalize(entryName);\n    return norm != null && !norm.startsWith(\"../\");\n}","typeGuard":"// Java has no runtime type narrowing; use a predicate\njava.util.function.Predicate<String> safeEntry =\n    name -> Paths.normalize(name) != null && !Paths.normalize(name).startsWith(\"../\");","tryCatchPattern":"try {\n    extractor.extract();\n} catch (IOException e) {\n    if (e.getMessage().contains(\"Zip slip\")) {\n        Log.e(TAG, \"Refusing malicious backup archive\", e);\n        deletePartialOutput(destDir);\n    } else throw e;\n}","preventionTips":["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"],"tags":["security","zip-slip","path-traversal"],"backgroundTag":"path-traversal-blocked","analyzedSha":"0152f468fc9463ee02dc2ca83f6fe4989a2c4ca5","analyzedAt":"2026-09-12T14:03:37.243Z","contentChangedAt":"2026-09-12T14:03:37.243Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}