jeecgboot/JeecgBoot · error · JeecgBootException

非法存储路径,路径包含遍历字符: {storePath}

Error message

非法存储路径,路径包含遍历字符: {storePath}

What it means

Thrown by FileDownloadUtils.download2DiskFromNet when the computed canonical path of storePath does not equal its absolute path. This is a CWE-22 path-traversal guard added for issue 9437: it runs after SsrfFileTypeFilter.checkPathTraversal and confirms the path contains no '../' traversal or symlink resolution that escapes the intended directory. The JeecgBootException signals the caller passed an unsafe storage path.

Source

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

    }

    /**
     * 下载网络资源到磁盘
     *
     * @param fileUrl
     * @param storePath
     * @author chenrui
     * @date 2024/1/19 10:09
     */
    public static String download2DiskFromNet(String fileUrl, String storePath) {
        //update-begin---author:liusq ---date:2026-03-30  for:【issues/9437】修复download2DiskFromNet storePath路径遍历漏洞(CWE-22)-----------
        // 路径遍历校验:拦截 ../ 等遍历字符,并确保规范化路径与原始路径一致
        SsrfFileTypeFilter.checkPathTraversal(storePath);
        try {
            String canonicalPath = new File(storePath).getCanonicalPath();
            String absolutePath = new File(storePath).getAbsolutePath();
            if (!canonicalPath.equals(absolutePath)) {
                throw new JeecgBootException("非法存储路径,路径包含遍历字符: " + storePath);
            }
        } catch (IOException e) {
            throw new JeecgBootException("存储路径校验失败: " + storePath, e);
        }
        //update-end---author:liusq ---date:2026-03-30  for:【issues/9437】修复download2DiskFromNet storePath路径遍历漏洞(CWE-22)-----------
        //update-begin---author:zhangdaihao ---date:2026-04-15  for:【issues/9553】下载网络资源前增加SSRF校验-----------
        SsrfFileTypeFilter.checkSsrfHttpUrl(fileUrl);
        //update-end---author:zhangdaihao ---date:2026-04-15  for:【issues/9553】下载网络资源前增加SSRF校验-----------
        try {
            URL url = new URL(fileUrl);
            URLConnection conn = url.openConnection();
            // 设置超时间为3秒
            conn.setConnectTimeout(3 * 1000);
            // 防止屏蔽程序
            conn.setRequestProperty("User-Agent", "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)");
            // 确保目录存在
            File file = ensureDestFileDir(storePath);
            try (InputStream inStream = conn.getInputStream();

View on GitHub (pinned to 96fb33f5ec)

Solutions

  1. Pass a clean, pre-normalized absolute path as storePath — compute it with Paths.get(baseDir, fileName).normalize().toAbsolutePath() and confirm it startsWith(baseDir) before calling download2DiskFromNet.
  2. Strip any '../' or '.\' sequences from the storePath and re-derive it from a trusted base directory constant.
  3. If the mismatch is caused by a symlinked storage volume, point the storage config at the real (canonical) path so absolute == canonical.
  4. At the calling controller, validate the storePath/fileName with a whitelist regex (e.g. no path separators in the filename portion) before it reaches this method.

Example fix

// before
String storePath = uploadDir + "/" + request.getParameter("fileName");
FileDownloadUtils.download2DiskFromNet(fileUrl, storePath);

// after
Path base = Paths.get(uploadDir).toAbsolutePath().normalize();
Path resolved = base.resolve(request.getParameter("fileName")).normalize();
if (!resolved.startsWith(base)) {
    throw new IllegalArgumentException("Invalid file path");
}
FileDownloadUtils.download2DiskFromNet(fileUrl, resolved.toString());
Defensive patterns

Strategy: validation

Validate before calling

Path base = Paths.get(uploadDir).toAbsolutePath().normalize();
Path resolved = base.resolve(fileName).normalize();
if (!resolved.startsWith(base)) {
    throw new IllegalArgumentException("storePath escapes base directory: " + resolved);
}
FileDownloadUtils.download2DiskFromNet(fileUrl, resolved.toString());

Type guard

null

Try / catch

try {
    FileDownloadUtils.download2DiskFromNet(fileUrl, resolved.toString());
} catch (JeecgBootException e) {
    log.warn("下载失败,路径校验未通过: {}", e.getMessage());
    return Result.error("文件路径不合法");
}

Prevention

When it happens

Trigger: Calling FileDownloadUtils.download2DiskFromNet(fileUrl, storePath) where storePath contains '../', '.' segments, or resolves through symlinks so that new File(storePath).getCanonicalPath() differs from getAbsolutePath(). Any storePath sourced from user input or request parameters without sanitization.

Common situations: Upload/download directory configured with a relative path containing '..'; storage base directory is a symlink; storePath is built by concatenating untrusted user input (filename from upload) onto a base dir without normalization; path constructed on Windows with case differences that make canonical != absolute.

Related errors


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