{"record":{"id":"e07e844a3a7eebf0","repo":"beemdevelopment/Aegis","slug":"attempted-to-write-outside-of-the-parent-directory","errorCode":null,"errorMessage":"Attempted to write outside of the parent directory","messagePattern":"Attempted to write outside of the parent directory","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"critical","filePath":"app/src/main/java/com/beemdevelopment/aegis/icons/IconPackManager.java","lineNumber":82,"sourceCode":"    public IconPack importPack(File inFile) throws IconPackException {\n        try {\n            // read and parse the icon pack definition file of the icon pack\n            ZipFile zipFile = new ZipFile(inFile);\n            FileHeader packHeader = zipFile.getFileHeader(_packDefFilename);\n            if (packHeader == null) {\n                throw new IOException(\"Unable to find pack.json in the root of the ZIP file\");\n            }\n            IconPack pack;\n            byte[] defBytes;\n            try (ZipInputStream inStream = zipFile.getInputStream(packHeader)) {\n                defBytes = IOUtils.readAll(inStream);\n                pack = IconPack.fromBytes(defBytes);\n            }\n\n            // create a new directory to store the icon pack, based on the UUID and version\n            File packDir = getIconPackDir(pack);\n            if (!packDir.getCanonicalPath().startsWith(_iconsBaseDir.getCanonicalPath() + File.separator)) {\n                throw new IOException(\"Attempted to write outside of the parent directory\");\n            }\n            if (packDir.exists()) {\n                throw new IconPackExistsException(pack);\n            }\n            IconPack existingPack = getIconPackByUUID(pack.getUUID());\n            if (existingPack != null) {\n                throw new IconPackExistsException(existingPack);\n            }\n            if (!packDir.exists() && !packDir.mkdirs()) {\n                throw new IOException(String.format(\"Unable to create directories: %s\", packDir.toString()));\n            }\n\n            // extract each of the defined icons to the icon pack directory\n            for (IconPack.Icon icon : pack.getIcons()) {\n                File destFile = new File(packDir, icon.getRelativeFilename());\n                if (!destFile.getCanonicalPath().startsWith(packDir.getCanonicalPath() + File.separator)) {\n                    throw new IOException(\"Attempted to write outside of the icon pack directory\");\n                }","sourceCodeStart":64,"sourceCodeEnd":100,"githubUrl":"https://github.com/beemdevelopment/Aegis/blob/d6f4e5925a97e4e91593f1542085eae03432a759/app/src/main/java/com/beemdevelopment/aegis/icons/IconPackManager.java#L64-L100","documentation":"After parsing the pack, importPack builds the destination directory from the pack's UUID/version and verifies its canonical path stays inside Aegis's private icons base directory. If the canonical path escapes the base dir, the code refuses to write and throws this IOException, defending against ZIP-slip style attacks where crafted metadata targets paths like ../../databases.","triggerScenarios":"Importing a crafted icon pack whose UUID/version (used to build the destination path) resolve to a canonical path outside the icons base directory — e.g. an identifier containing ../ traversal segments.","commonSituations":"Deliberately malicious icon packs designed to overwrite the Aegis vault or other app files (covered by testMaliciousIconPackCannotOverwriteVaultFile); extremely unlikely from legitimate packs, but possible if pack.json fields were tampered with.","solutions":["Do not import icon packs from untrusted sources — this error indicates the pack is malicious or malformed","Inspect pack.json for traversal characters (../, absolute paths) in the uuid/version-derived fields","Obtain a clean pack.json with a canonical UUID and repackage the ZIP","Report the malicious pack to its distributor"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"File packDir = new File(iconsBaseDir, uuid + \"/\" + version);\nString canonical = packDir.getCanonicalPath();\nif (!canonical.startsWith(iconsBaseDir.getCanonicalPath() + File.separator)) {\n    throw new IconPackException(\"Unsafe pack path\");\n}","typeGuard":"boolean isInsideParent(File child, File parent) throws IOException {\n    return child.getCanonicalPath().startsWith(parent.getCanonicalPath() + File.separator);\n}","tryCatchPattern":"try {\n    iconPackManager.importPack(file);\n} catch (IconPackException e) {\n    Log.e(TAG, \"Icon pack rejected (possible path traversal)\", e);\n    UiHelper.showDialog(context, R.string.malicious_icon_pack);\n}","preventionTips":["Only import icon packs from trusted sources","Reject any pack.json whose identifiers contain ../ or absolute paths","Keep the canonical-path containment check enabled in your own forks","Scan third-party packs before redistributing"],"tags":["security","path-traversal","zip-slip","icon-pack"],"backgroundTag":"path-traversal-blocked","analyzedSha":"d6f4e5925a97e4e91593f1542085eae03432a759","analyzedAt":"2026-09-08T00:46:31.111Z","contentChangedAt":"2026-09-08T00:46:31.111Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}