{"record":{"id":"b20dbda9558f7ea1","repo":"jeecgboot/JeecgBoot","slug":"error-b20dbd","errorCode":null,"errorMessage":"上传业务路径包含非法字符！","messagePattern":"上传业务路径包含非法字符！","errorType":"validation","errorClass":"JeecgBootException","httpStatus":null,"severity":"critical","filePath":"jeecg-boot/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/filter/SsrfFileTypeFilter.java","lineNumber":278,"sourceCode":"            stringBuilder.append(hv);\n        }\n        return stringBuilder.toString();\n    }\n\n    /**\n     * 路径安全校验\n     */\n    private static void validatePathSecurity(String customPath) throws JeecgBootException {\n        if (customPath == null || customPath.trim().isEmpty()) {\n            return;\n        }\n\n        // 统一分隔符为 /\n        String normalized = customPath.replace(\"\\\\\", \"/\");\n\n        // 1. 防止路径遍历攻击\n        if (normalized.contains(\"..\") || normalized.contains(\"~\")) {\n            throw new JeecgBootException(\"上传业务路径包含非法字符！\");\n        }\n\n        // 2. 限制路径深度\n        int depth = normalized.split(\"/\").length;\n        if (depth > 5) {\n            throw new JeecgBootException(\"上传业务路径深度超出限制！\");\n        }\n\n        // 3. 限制字符集（只允许字母、数字、下划线、横线、斜杠）\n        if (!normalized.matches(\"^[a-zA-Z0-9/_-]+$\")) {\n            throw new JeecgBootException(\"上传业务路径包含非法字符！\");\n        }\n    }\n\n    /**\n     * 校验文件路径安全性，防止路径遍历攻击\n     * @param filePath 文件路径\n     */","sourceCodeStart":260,"sourceCodeEnd":296,"githubUrl":"https://github.com/jeecgboot/JeecgBoot/blob/96fb33f5ec68516da0b0147da06b2eb0419e063a/jeecg-boot/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/filter/SsrfFileTypeFilter.java#L260-L296","documentation":"Thrown by SsrfFileTypeFilter.validatePathSecurity when the normalized customPath contains '..' or '~'. This is the path-traversal guard for upload business paths — it blocks directory escapes before the upload is written. The path is normalized (backslashes -> '/') first, so '\\\\..\\\\' is also caught.","triggerScenarios":"An upload API call with customPath containing '../', a leading '~' (home reference), or backslash variants like '..\\\\..\\\\etc'. Common when the client constructs the path from user input without sanitization.","commonSituations":"A filename or folder field concatenated into customPath; an attacker probing for arbitrary file write; a misbehaving client that sends absolute paths or Windows-style paths.","solutions":["Strip '..' and '~' from customPath on the client before submitting; only use simple relative folder names.","Server-side, generate customPath from trusted metadata (tenant id, date) rather than raw user input.","Reject any absolute path or path containing path-traversal sequences at the DTO validation layer.","Confirm the upload form sends only a flat business category (e.g. 'avatar', 'report')."],"exampleFix":"// before\ncustomPath = \"../../etc/passwd\";\ncheckUploadFileType(file, customPath); // throws\n\n// after\ncustomPath = \"avatar\";\ncheckUploadFileType(file, customPath);","handlingStrategy":"validation","validationCode":"String n = customPath == null ? \"\" : customPath.replace(\"\\\\\",\"/\");\nif (n.contains(\"..\") || n.contains(\"~\")) throw new IllegalArgumentException(\"traversal\");","typeGuard":"public static boolean pathNoTraversal(String p){\n    String n = p == null ? \"\" : p.replace(\"\\\\\",\"/\");\n    return !n.contains(\"..\") && !n.contains(\"~\");\n}","tryCatchPattern":"try { SsrfFileTypeFilter.checkUploadFileType(file, customPath); }\ncatch (JeecgBootException e) { if (e.getMessage().contains(\"非法\")) badRequest(e.getMessage()); }","preventionTips":["Generate customPath from trusted metadata only.","Reject absolute paths at the DTO layer.","Use flat folder categories."],"tags":["file-upload","path-traversal","security","validation","jeecg-boot"],"backgroundTag":null,"analyzedSha":"96fb33f5ec68516da0b0147da06b2eb0419e063a","analyzedAt":"2026-08-14T00:04:16.786Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}