jeecgboot/JeecgBoot · critical · JeecgBootException

非法业务路径,禁止访问上传目录之外的路径: ${bizPath}

Error message

非法业务路径,禁止访问上传目录之外的路径: ${bizPath}

What it means

A second path-traversal guard (CWE-22) in CommonUtils.uploadLocal, covering the MultipartFile-based upload flow (vs the byte[] flow in error 14). It canonicalizes both the uploadpath root and the uploadpath+bizPath target via getCanonicalFile(), then asserts the target starts with the upload dir. If a bizPath escapes the upload directory after canonicalization, it throws JeecgBootException. Added for issues/9428. It also runs SsrfFileTypeFilter.checkUploadFileType to block disallowed file types.

Source

Thrown at jeecg-boot/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/CommonUtils.java:180

    }
    /**
     * 本地文件上传
     * @param mf 文件
     * @param bizPath  自定义路径
     * @return
     */
    public static String uploadLocal(MultipartFile mf,String bizPath,String uploadpath){
        try {
            // 文件安全校验,防止上传漏洞文件
            SsrfFileTypeFilter.checkUploadFileType(mf, bizPath);
            
            String fileName = null;
            //update-begin---author:liusq ---date:2026-03-30  for:【issues/9428】修复uploadLocal bizPath路径遍历漏洞(CWE-22)-----------
            // 路径遍历校验:规范化后确保目标目录在uploadpath内
            File uploadDir = new File(uploadpath).getCanonicalFile();
            File file = new File(uploadpath + File.separator + bizPath + File.separator).getCanonicalFile();
            if (!file.toPath().startsWith(uploadDir.toPath())) {
                throw new JeecgBootException("非法业务路径,禁止访问上传目录之外的路径: " + bizPath);
            }
            //update-end---author:liusq ---date:2026-03-30  for:【issues/9428】修复uploadLocal bizPath路径遍历漏洞(CWE-22)-----------
            if (!file.exists()) {
                // 创建文件根目录
                file.mkdirs();
            }
            // 获取文件名
            String orgName = mf.getOriginalFilename();
            // 无中文情况下进行转码
            if (orgName != null && !CommonUtils.ifContainChinese(orgName)) {
                orgName = new String(orgName.getBytes(StandardCharsets.ISO_8859_1), StandardCharsets.UTF_8);
            }
            orgName = CommonUtils.getFileName(orgName);
            if(orgName.indexOf(SymbolConstant.SPOT)!=-1){
                fileName = orgName.substring(0, orgName.lastIndexOf(".")) + "_" + System.currentTimeMillis() + orgName.substring(orgName.lastIndexOf("."));
            }else{
                fileName = orgName+ "_" + System.currentTimeMillis();
            }

View on GitHub (pinned to 96fb33f5ec)

Solutions

  1. Validate and sanitize bizPath server-side before reaching uploadLocal: reject '..' and absolute paths.
  2. Use a fixed allow-list of subdirectories for bizPath.
  3. Ensure the configured uploadpath is a real, non-symlinked absolute directory.
  4. Run SsrfFileTypeFilter checks earlier and fail fast with a clear message.

Example fix

// before — bizPath built from unvalidated input
String bizPath = request.getParameter("path"); // "../secret"

// after — validate against allow-list
String bizPath = sanitizeBizPath(request.getParameter("path"));
if (bizPath == null) throw new IllegalArgumentException("invalid bizPath");
Defensive patterns

Strategy: validation

Validate before calling

// Validate bizPath against the upload dir before uploadLocal
public static void safeUploadLocal(MultipartFile mf, String bizPath, String uploadpath) {
  File dir = new File(uploadpath + File.separator + bizPath).getCanonicalFile();
  File root = new File(uploadpath).getCanonicalFile();
  if (!dir.toPath().startsWith(root.toPath()))
    throw new IllegalArgumentException("bizPath escapes upload dir");
  CommonUtils.uploadLocal(mf, bizPath, uploadpath);
}

Type guard

public static boolean bizPathWithinRoot(String bizPath, String uploadpath) throws IOException {
  Path root = Paths.get(uploadpath).toRealPath();
  Path target = Paths.get(uploadpath, bizPath).toAbsolutePath().normalize();
  return target.startsWith(root);
}

Try / catch

try {
  CommonUtils.uploadLocal(mf, bizPath, uploadpath);
} catch (JeecgBootException e) {
  response.sendError(400, "Illegal upload path");
}

Prevention

When it happens

Trigger: A multipart upload request whose bizPath parameter resolves (after symlink resolution and normalization via getCanonicalFile) to a location outside the configured uploadpath. Attacker-controlled bizPath with traversal sequences or symlink-laden base paths.

Common situations: Security testing of the upload endpoint; a frontend bug concatenating paths with '..'; a shared upload root where a symlink points outside; misconfigured uploadpath that itself contains traversal segments.

Related errors


AI-assisted analysis of jeecgboot/JeecgBoot@96fb33f5ec (2026-08-14). Data as JSON: /api/errors/714ad5fd2572d4d5. Report an issue: GitHub.