{"record":{"id":"e93618f671d4d140","repo":"alibaba/canal","slug":"invalid-destination-path","errorCode":null,"errorMessage":"Invalid destination path","messagePattern":"Invalid destination path","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"common/src/main/java/com/alibaba/otter/canal/common/utils/FileUtils.java","lineNumber":107,"sourceCode":"        return res.toString();\n    }\n\n    /**\n     * 校验自定义的文件名，是否在允许的基目录范围内，如何合法就返回全路径，否则就直接报错\n     *\n     * @param baseDir\n     * @param destination\n     * @return\n     */\n    public static String validateFileName(String baseDir, String destination) {\n        try {\n            // 验证 destination 是否在允许的基目录范围内\n            String basePath = new File(baseDir).getCanonicalPath();\n            String fullPath = new File(basePath, destination).getCanonicalPath();\n\n            // 检查 fullPath 是否以 basePath 开头\n            if (!fullPath.startsWith(basePath + File.separator)) {\n                throw new IllegalArgumentException(\"Invalid destination path\");\n            }\n\n            return fullPath;\n        } catch (IOException e) {\n            throw new RuntimeException(\"Failed to read file\", e);\n        }\n    }\n\n    public static void main(String[] args) throws IOException {\n        String fullPath = validateFileName(\"/tmp/\", \"1.txt\");\n        System.out.println(fullPath);\n        System.out.println(org.apache.commons.io.FileUtils.readLines(new File(fullPath)));\n\n        fullPath = validateFileName(\"/tmp/\", \"test\");\n        fullPath = validateFileName(fullPath,\"1.txt\");\n        System.out.println(fullPath);\n        System.out.println(org.apache.commons.io.FileUtils.readLines(new File(fullPath)));\n","sourceCodeStart":89,"sourceCodeEnd":125,"githubUrl":"https://github.com/alibaba/canal/blob/87be50e87686a3e8af08c368d0e1ffd1f59eb04a/common/src/main/java/com/alibaba/otter/canal/common/utils/FileUtils.java#L89-L125","documentation":"Thrown by FileUtils.validateFileName() as a path-traversal guard. It resolves both baseDir and the combined baseDir+destination to their canonical (absolute, symlink-resolved) paths, then checks that the full path starts with basePath + File.separator. If the destination contains `../` sequences or symlinks that escape the base directory, the check fails and this exception is thrown.","triggerScenarios":"Calling validateFileName(baseDir, destination) where destination resolves outside baseDir — e.g. destination contains `../` that escapes, or a symlink within the path points outside baseDir, or destination is an absolute path pointing elsewhere.","commonSituations":"User-supplied or config-supplied file paths are used without sanitization; canal destination or instance name contains traversal characters; a symlink in the data directory resolves outside the allowed base; the baseDir itself is relative and resolves unexpectedly.","solutions":["Ensure the destination parameter contains no `../` sequences or absolute path prefixes.","Verify that no symlinks within the base directory tree resolve to locations outside baseDir.","Pass an absolute, canonical baseDir to avoid ambiguity in path resolution.","Sanitize user/config-provided path components by rejecting any input containing `..` or starting with `/`."],"exampleFix":"// before — user input used directly as destination\nString dest = request.getParam(\"name\"); // could be \"../../etc/passwd\"\nString path = FileUtils.validateFileName(baseDir, dest);\n\n// after — sanitize input\nString dest = request.getParam(\"name\");\nif (dest.contains(\"..\") || dest.startsWith(\"/\")) {\n    throw new IllegalArgumentException(\"Invalid name\");\n}\nString path = FileUtils.validateFileName(baseDir, dest);","handlingStrategy":"validation","validationCode":"// Sanitize destination before calling validateFileName\nif (destination == null || destination.contains(\"..\") || destination.startsWith(\"/\")\n    || destination.contains(File.separator + \"..\")) {\n    throw new IllegalArgumentException(\"Invalid destination: path traversal detected\");\n}\nString safePath = FileUtils.validateFileName(baseDir, destination);","typeGuard":"null","tryCatchPattern":"try {\n    String path = FileUtils.validateFileName(baseDir, destination);\n} catch (IllegalArgumentException e) {\n    if (\"Invalid destination path\".equals(e.getMessage())) {\n        logger.warn(\"Rejected path traversal attempt: baseDir={}, dest={}\", baseDir, destination);\n    }\n    throw e;\n}","preventionTips":["Reject any user/config-supplied path containing `..` or starting with `/`.","Prefer whitelisting allowed characters in file name components.","Use absolute baseDir paths to reduce ambiguity.","Never trust client-supplied paths without canonicalization and containment checks."],"tags":["security","path-traversal","file-validation","canal-common"],"backgroundTag":null,"analyzedSha":"87be50e87686a3e8af08c368d0e1ffd1f59eb04a","analyzedAt":"2026-08-14T04:30:11.918Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}