jeecgboot/JeecgBoot · critical · JeecgBootException
文件路径包含非法字符
Error message
文件路径包含非法字符
What it means
This error is thrown when path traversal is detected during AI attachment file resolution. The code resolves the fileRef against the upload directory root, normalizes the path, and checks if the resolved target still starts with the root directory. If not (indicating a ../ escape attempt), it rejects the request. This is a security guard against CWE-22 path traversal attacks on AI chat attachment files.
Source
Thrown at jeecg-boot/jeecg-boot-module/jeecg-boot-module-airag/src/main/java/org/jeecg/modules/airag/app/service/impl/AiragChatServiceImpl.java:2197
}
String tempFilePath = tempDir + safeFileName;
//update-begin---author:zhangdaihao ---date:20260427 for:[issues/9578]AI附件下载 SSRF 校验,拒绝 loopback/link-local------------
// /airag/chat/send 端点为 @IgnoreAuth 无认证,AI 聊天解析附件存在 SSRF 风险;
// 沿用与 #9553 一致的基础 SSRF 校验(拒绝 loopback / link-local),保留对企业内网 MinIO/OSS 的兼容。
SsrfFileTypeFilter.checkSsrfHttpUrl(fileRef);
//update-end-----author:zhangdaihao ---date:20260427 for:[issues/9578]AI附件下载 SSRF 校验,拒绝 loopback/link-local------------
FileDownloadUtils.download2DiskFromNet(fileRef, tempFilePath);
return new File(tempFilePath);
}
//update-begin---author:wangshuai ---date:2026-04-13 for:【issues/9519】AI附件处理路径遍历漏洞:规范化路径并强制校验沙箱范围---
// 本地附件:1) 先做字符级路径遍历检查;2) 规范化路径后必须仍在 uploadpath 下,阻止 ../ 逃逸
java.nio.file.Path root = Paths.get(uploadpath).toAbsolutePath().normalize();
SsrfFileTypeFilter.checkPathTraversal(fileRef);
String relativePath = fileRef.replaceAll("^[\\\\/]+", "");
java.nio.file.Path target = root.resolve(relativePath).toAbsolutePath().normalize();
if (!target.startsWith(root)) {
log.error("检测到路径遍历攻击! fileRef: {}, 解析后: {}", relativePath, target);
throw new JeecgBootException("文件路径包含非法字符");
}
return target.toFile();
//update-end---author:wangshuai ---date:2026-04-13 for:【issues/9519】AI附件处理路径遍历漏洞:规范化路径并强制校验沙箱范围---
}
//================================================= end【QQYUN-14261】【AI】AI助手,支持多模态能力- 文档========================================
/**
* ai创作
*
* @param aiWriteGenerateVo
* @return
*/
@Override
public SseEmitter genAiWriter(AiWriteGenerateVo aiWriteGenerateVo) {
String activeMode = "compose";
String reply = "reply";
ChatSendParams sendParams = new ChatSendParams();View on GitHub (pinned to 96fb33f5ec)
Solutions
- This is a security guard working correctly — do not disable it. Investigate the source of the malicious fileRef value.
- If the fileRef is legitimate, ensure it does not contain ../, ..\, or absolute path prefixes — use a simple relative filename only.
- Audit the client-side code that generates the fileRef to ensure it only produces safe relative paths.
- Check the server logs for the full fileRef and resolved target path to understand the attempted traversal.
Example fix
// before (client) — sending a path with traversal characters String fileRef = "../../uploads/document.pdf"; // after — sending a clean relative filename only String fileRef = "document.pdf";
Defensive patterns
Strategy: validation
Validate before calling
// Server-side: validate fileRef before path resolution
public static boolean isSafeFileRef(String fileRef) {
if (fileRef == null || fileRef.isEmpty()) return false;
// Reject path traversal patterns
if (fileRef.contains("..") || fileRef.contains("%2e%2e")) return false;
// Reject absolute paths
if (fileRef.startsWith("/") || fileRef.startsWith("\\")) return false;
// Only allow alphanumeric, dash, underscore, dot, and standard separators
return fileRef.matches("[a-zA-Z0-9._\\-/]+");
} Type guard
// Normalize and validate that resolved path stays within root
public static boolean isWithinUploadRoot(String uploadpath, String fileRef) {
try {
Path root = Paths.get(uploadpath).toAbsolutePath().normalize();
Path target = root.resolve(fileRef.replaceAll("^[\\\\/]+", "")).toAbsolutePath().normalize();
return target.startsWith(root);
} catch (Exception e) {
return false;
}
} Try / catch
// This is a security guard — the exception should not be caught and suppressed.
// Instead, log the security event and return an error to the client.
try {
File file = resolveAttachmentFile(fileRef, uploadpath);
// process file
} catch (JeecgBootException e) {
if (e.getMessage().contains("非法字符")) {
log.warn("[SECURITY] Path traversal attempt blocked: fileRef={}", fileRef);
auditLogService.recordSecurityEvent("PATH_TRAVERSAL_ATTEMPT", fileRef);
}
throw e;
} Prevention
- Never accept user-supplied file paths — use database-stored file references with UUIDs
- Sanitize file references at the API boundary before they reach the file system layer
- Use a whitelist of allowed filename patterns rather than a blacklist of dangerous ones
- Implement audit logging for path traversal attempts
- Store uploaded files with generated UUIDs, not user-supplied filenames
When it happens
Trigger: A user sends a file reference (fileRef) like '../../../etc/passwd' or '..\..\config\application.yml' to an AI chat endpoint that processes local file attachments. SsrfFileTypeFilter.checkPathTraversal first catches character-level traversal patterns, and the normalized path check (target.startsWith(root)) catches any remaining escape attempts.
Common situations: Malicious input attempting directory traversal to access system files. Legitimate file references with unusual but safe path characters that trigger a false positive in SsrfFileTypeFilter. Race condition where the upload directory path changes between resolution and normalization.
Related errors
- 非法文件路径,禁止访问上传目录之外的文件:
- Illegal access to path outside of base directory.
- 非法业务路径,禁止访问上传目录之外的路径: ${bizPath}
- 非法存储路径,路径包含遍历字符: {storePath}
- 非法文件路径,禁止访问上传目录之外的文件: {imageUrl}
AI-assisted analysis of jeecgboot/JeecgBoot@96fb33f5ec (2026-08-14).
Data as JSON: /api/errors/a1f9657835b469db.
Report an issue: GitHub.