{"record":{"id":"7f2c51bb8a3579bb","repo":"MuntashirAkon/AppManager","slug":"zip-slip-vulnerability-detected-expected-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: (.+?)\nActual path: (.+?)","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"critical","filePath":"app/src/main/java/io/github/muntashirakon/AppManager/utils/TarUtils.java","lineNumber":158,"sourceCode":"        Pattern[] exclusionPatterns;\n        if (exclusions != null) {\n            exclusionPatterns = new Pattern[exclusions.length];\n            for (int i = 0; i < exclusions.length; ++i) {\n                exclusionPatterns[i] = Pattern.compile(exclusions[i]);\n            }\n        } else exclusionPatterns = null;\n        // Run extraction\n        try (SplitInputStream sis = new SplitInputStream(sources);\n             BufferedInputStream bis = new BufferedInputStream(sis);\n             InputStream is = createDecompressedStream(bis, type)) {\n            try (TarArchiveInputStream tis = new TarArchiveInputStream(is)) {\n                String realDestPath = dest.getRealFilePath();\n                TarArchiveEntry entry;\n                while ((entry = tis.getNextEntry()) != 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                    Path file;\n                    if (entry.isDirectory()) {\n                        file = dest.createDirectoriesIfRequired(filename);\n                    } else file = dest.createNewArbitraryFile(filename, null);\n                    if (!entry.isDirectory() && (!Paths.isUnderFilter(file, dest, filterPatterns)\n                            || Paths.willExclude(file, dest, exclusionPatterns))) {\n                        // Unlike create, there's no efficient way to detect if a directory contains any filters.\n                        // Therefore, directory can't be filtered during extraction\n                        file.delete();\n                        continue;\n                    }\n                    // Check if the given entry is a link.\n                    if (entry.isSymbolicLink() && file.getFilePath() != null) {\n                        if ((!Paths.isUnderFilter(file, dest, filterPatterns) || Paths.willExclude(file, dest, exclusionPatterns))) {\n                            // Do not create this link even if it is a directory","sourceCodeStart":140,"sourceCodeEnd":176,"githubUrl":"https://github.com/MuntashirAkon/AppManager/blob/0152f468fc9463ee02dc2ca83f6fe4989a2c4ca5/app/src/main/java/io/github/muntashirakon/AppManager/utils/TarUtils.java#L140-L176","documentation":"TarUtils.extract performs an early zip-slip check on every tar entry: entry names are normalized (Paths.normalize) and rejected if normalization returns null or the result still starts with '../'. Throwing IOException(\"Zip slip vulnerability detected!...\") prevents creating any files for an entry whose name would escape the destination directory via path traversal. The message contrasts the expected destination with the actual (traversal) path. This is a protective security error, not a bug in the caller's code.","triggerScenarios":"Extracting a tar/zip archive containing entries with names like '../../etc/passwd', absolute paths, or names that after symlink/parent normalization leave the destination directory (dest.getRealFilePath() prefix check fails).","commonSituations":"Processing untrusted or attacker-supplied archives (downloaded backups, shared tarballs); archives crafted by a malicious packager; archives produced on other systems with '..' segments; symlink entries inside the archive pointing outside the destination (caught later at 419).","solutions":["Do not extract the archive if it comes from an untrusted source; reject it and inform the user","Sanitize/rebuild entry names server-side before archiving (strip leading '/' and '..' segments)","Inspect the archive listing first (list entries without extracting) and reject any with '..' or absolute paths","Catch IOException and surface the message — it identifies the offending entry name"],"exampleFix":"// before\nTarUtils.extract(input, destDir, ...); // throws on malicious entry\n// after\ntry {\n    TarUtils.extract(input, destDir, ...);\n} catch (IOException e) {\n    if (e.getMessage().contains(\"Zip slip\")) {\n        throw new SecurityException(\"Archive rejected: \" + e.getMessage(), e);\n    }\n    throw e;\n}","handlingStrategy":"validation","validationCode":"for (String entryName : archiveEntryNames) {\n    String normalized = Paths.normalize(entryName);\n    if (normalized == null || normalized.startsWith(\"../\") || entryName.startsWith(\"/\")) {\n        throw new SecurityException(\"Unsafe entry: \" + entryName);\n    }\n}","typeGuard":"boolean isSafeEntryName(String name) {\n    String n = Paths.normalize(name);\n    return n != null && !n.startsWith(\"../\") && !n.startsWith(\"/\");\n}","tryCatchPattern":"try {\n    TarUtils.extract(in, dest, filters);\n} catch (IOException e) {\n    if (e.getMessage().contains(\"Zip slip\")) {\n        throw new SecurityException(\"Path traversal blocked: \" + e.getMessage(), e);\n    }\n    throw e;\n}","preventionTips":["List archive entries and reject any with '..' or absolute paths before extraction","Only extract archives from trusted, verified sources","Extract into a fresh per-archive directory under app-internal storage"],"tags":["security","zip-slip","path-traversal","archive"],"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-14T11:17:12.474Z"}