{"record":{"id":"8ea15f16945fa761","repo":"jeecgboot/JeecgBoot","slug":"imageurl","errorCode":null,"errorMessage":"非法文件路径，禁止访问上传目录之外的文件: {imageUrl}","messagePattern":"非法文件路径，禁止访问上传目录之外的文件: (.+?)","errorType":"validation","errorClass":"JeecgBootException","httpStatus":null,"severity":"error","filePath":"jeecg-boot/jeecg-boot-module/jeecg-boot-module-airag/src/main/java/org/jeecg/modules/airag/wordtpl/utils/WordUtil.java","lineNumber":733,"sourceCode":"                    conn.setRequestProperty(\"User-Agent\", \"Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)\");\n                    in = conn.getInputStream();\n                } catch (IOException e) {\n                    log.error(e.getMessage(), e);\n                    throw new JeecgBootException(e);\n                }\n                //update-end---author:wangshuai ---date:2026-05-11  for：[issues/9610]【安全漏洞】修复WordUtil.addImage存储型SSRF漏洞(CWE-918)-----------\n            } else {\n                //update-begin---author:liusq ---date:2026-03-30  for：[issues/9429]【安全漏洞】修复WordUtil.addImage路径遍历漏洞(CWE-22)-----------\n                String uploadPath = SpringContextUtils.getApplicationContext()\n                        .getEnvironment()\n                        .getProperty(\"jeecg.path.upload\", \"\");\n                // 将本地图片读取到 InputStream\n                String filePath = uploadPath + File.separator + imageUrl;\n                // 路径遍历校验：规范化后确保文件在uploadPath目录内\n                File uploadDir = new File(uploadPath).getCanonicalFile();\n                File targetFile = new File(filePath).getCanonicalFile();\n                if (!targetFile.toPath().startsWith(uploadDir.toPath())) {\n                    throw new JeecgBootException(\"非法文件路径，禁止访问上传目录之外的文件: \" + imageUrl);\n                }\n                in = new FileInputStream(targetFile);\n                //update-end---author:liusq ---date:2026-03-30  for：[issues/9429]【安全漏洞】修复WordUtil.addImage路径遍历漏洞(CWE-22)-----------\n            }\n            XWPFRun run = paragraph.createRun();\n\n            String display = content.getString(\"imgDisplay\");\n\n            if(oConvertUtils.isNotEmpty(display) && display.toLowerCase().startsWith(\"float-\")){\n                // 浮动图片\n                String behindDoc = \"0\";\n                if(!display.equalsIgnoreCase(\"float-bottom\")){\n                    behindDoc = \"1\";\n                }\n\n                int width = content.getIntValue(\"width\");\n                int height = content.getIntValue(\"height\");\n","sourceCodeStart":715,"sourceCodeEnd":751,"githubUrl":"https://github.com/jeecgboot/JeecgBoot/blob/96fb33f5ec68516da0b0147da06b2eb0419e063a/jeecg-boot/jeecg-boot-module/jeecg-boot-module-airag/src/main/java/org/jeecg/modules/airag/wordtpl/utils/WordUtil.java#L715-L751","documentation":"SECURITY control fixing CWE-22 (path traversal) in WordUtil.addImage(). When an image value is a local path (not a web URL), it is resolved under jeecg.path.upload and canonicalized. If the canonical target path does not start with the canonical upload-dir path, the request is rejected. The imageUrl is user/template-influenced, so this is a load-bearing guard -- never weaken it.","triggerScenarios":"A document template's image value contains '../' sequences, an absolute path, or a symlink that resolves outside the upload directory; getCanonicalFile() resolves the path beyond uploadPath.","commonSituations":"Malicious/templated image path supplied via document content; a symlink in the upload dir escaping it; imageUrl with a leading '/'.","solutions":["This guard is firing correctly -- inspect the rejected imageUrl payload.","If the access is legitimate, place the image under jeecg.path.upload and reference it by a relative path inside that dir.","Do NOT remove or relax the startsWith canonical check.","Audit logs for repeated attempts (possible attack)."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// caller-side: ensure image values are relative paths inside the upload dir\nString uploadPath = SpringContextUtils.getApplicationContext().getEnvironment()\n        .getProperty(\"jeecg.path.upload\", \"\");\nFile uploadDir = new File(uploadPath).getCanonicalFile();\nFile target = new File(uploadPath, imageUrl).getCanonicalFile();\nif (!target.toPath().startsWith(uploadDir.toPath())) {\n    throw new SecurityException(\"拒绝越界路径: \" + imageUrl);\n}","typeGuard":null,"tryCatchPattern":"// This is a security guard, not a recoverable error.\n// Catch only to log/audit, then deny.\ntry { addImage(paragraph, content); }\ncatch (JeecgBootException e) {\n    if (e.getMessage().contains(\"非法文件路径\")) {\n        log.warn(\"[安全审计] 路径遍历尝试被拦截: {}\", content.getString(\"value\"));\n    }\n    throw e;\n}","preventionTips":["Never accept absolute paths or '../' in image values from user content.","Treat repeated triggers as a security incident and audit them.","Do NOT relax the canonical startsWith check."],"tags":["security","path-traversal","cwe-22","word","image","guard"],"backgroundTag":null,"analyzedSha":"96fb33f5ec68516da0b0147da06b2eb0419e063a","analyzedAt":"2026-08-14T00:04:16.786Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}