{"record":{"id":"f6eaa4cb5deb41c3","repo":"iBotPeaches/Apktool","slug":"absolute-paths-are-not-allowed","errorCode":null,"errorMessage":"Absolute paths are not allowed","messagePattern":"Absolute paths are not allowed","errorType":"validation","errorClass":"InvalidPathException","httpStatus":null,"severity":"error","filePath":"brut.j.util/src/main/java/brut/util/BrutIO.java","lineNumber":108,"sourceCode":"\n    public static CRC32 calculateCrc(InputStream in) throws IOException {\n        CRC32 crc = new CRC32();\n        int bytesRead;\n        byte[] buffer = new byte[8192];\n        while ((bytesRead = in.read(buffer)) != -1) {\n            crc.update(buffer, 0, bytesRead);\n        }\n        return crc;\n    }\n\n    public static String sanitizePath(File baseDir, String path) throws InvalidPathException, IOException {\n        if (path == null || path.isEmpty()) {\n            throw new InvalidPathException(path, \"Path is null or empty\");\n        }\n\n        Path origPath = Paths.get(path);\n        if (origPath.isAbsolute()) {\n            throw new InvalidPathException(path, \"Absolute paths are not allowed\");\n        }\n\n        Path basePath = Paths.get(baseDir.getCanonicalPath());\n        Path resolvedPath = basePath.resolve(origPath).normalize();\n        if (!resolvedPath.startsWith(basePath)) {\n            throw new InvalidPathException(path, \"Path traverses outside the base directory\");\n        }\n\n        return basePath.relativize(resolvedPath).toString();\n    }\n}\n","sourceCodeStart":90,"sourceCodeEnd":120,"githubUrl":"https://github.com/iBotPeaches/Apktool/blob/79b63384d7d7e22917e6ea8b453272da7012515b/brut.j.util/src/main/java/brut/util/BrutIO.java#L90-L120","documentation":"Thrown by BrutIO.sanitizePath when the input path is absolute (e.g. '/etc/passwd' or 'C:\\x'). The method only accepts paths relative to a base directory so that the resolved result stays inside it. It is a security guard used when extracting or writing zip entries to prevent writing outside the target directory.","triggerScenarios":"Calling BrutIO.sanitizePath(baseDir, path) with any string for which Paths.get(path).isAbsolute() is true — a leading '/' on Unix, a drive letter or leading backslash on Windows, or a UNC path.","commonSituations":"Processing zip/apk entries that store absolute entry names; passing user-supplied or config-file paths that were written with leading separators; code ported from Windows to Unix or vice versa; tests feeding OS-native paths into the sanitizer.","solutions":["Strip the leading separator or convert the input to a path relative to baseDir before calling sanitizePath (e.g. path.startsWith(\"/\") ? path.substring(1) : path)","If the absolute path is legitimate, compute the relative portion yourself: baseDir.toPath().relativize(Paths.get(path)) and pass that result","Reject or skip absolute entries at the boundary where untrusted names enter (zip entry loop, config parser) instead of letting sanitizePath throw"],"exampleFix":"// before\nString rel = BrutIO.sanitizePath(baseDir, entryName); // entryName = \"/res/values.xml\"\n\n// after\nString cleaned = entryName.startsWith(\"/\") ? entryName.substring(1) : entryName;\nString rel = BrutIO.sanitizePath(baseDir, cleaned);","handlingStrategy":"validation","validationCode":"boolean isSafeRelative(String p) {\n    if (p == null || p.isEmpty()) return false;\n    Path path = Paths.get(p);\n    return !path.isAbsolute() && !p.contains(\"..\");\n}\n// use: if (isSafeRelative(entryName)) BrutIO.sanitizePath(baseDir, entryName); else skip();","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Normalize untrusted names at ingestion: strip leading '/' or '\\\\' and reject '..' segments before any filesystem call","Never build paths from raw config values or zip entry names without an isAbsolute() check","In tests, feed portable relative paths (forward slashes, no drive letters) on every OS"],"tags":["path-validation","security","filesystem","java"],"backgroundTag":null,"analyzedSha":"79b63384d7d7e22917e6ea8b453272da7012515b","analyzedAt":"2026-08-14T10:43:28.812Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}