{"record":{"id":"a1f9657835b469db","repo":"jeecgboot/JeecgBoot","slug":"error-a1f965","errorCode":null,"errorMessage":"文件路径包含非法字符","messagePattern":"文件路径包含非法字符","errorType":"validation","errorClass":"JeecgBootException","httpStatus":null,"severity":"critical","filePath":"jeecg-boot/jeecg-boot-module/jeecg-boot-module-airag/src/main/java/org/jeecg/modules/airag/app/service/impl/AiragChatServiceImpl.java","lineNumber":2197,"sourceCode":"            }\n            String tempFilePath = tempDir + safeFileName;\n            //update-begin---author:zhangdaihao ---date:20260427  for：[issues/9578]AI附件下载 SSRF 校验，拒绝 loopback/link-local------------\n            // /airag/chat/send 端点为 @IgnoreAuth 无认证，AI 聊天解析附件存在 SSRF 风险；\n            // 沿用与 #9553 一致的基础 SSRF 校验（拒绝 loopback / link-local），保留对企业内网 MinIO/OSS 的兼容。\n            SsrfFileTypeFilter.checkSsrfHttpUrl(fileRef);\n            //update-end-----author:zhangdaihao ---date:20260427  for：[issues/9578]AI附件下载 SSRF 校验，拒绝 loopback/link-local------------\n            FileDownloadUtils.download2DiskFromNet(fileRef, tempFilePath);\n            return new File(tempFilePath);\n        }\n        //update-begin---author:wangshuai ---date:2026-04-13  for：【issues/9519】AI附件处理路径遍历漏洞：规范化路径并强制校验沙箱范围---\n        // 本地附件：1) 先做字符级路径遍历检查；2) 规范化路径后必须仍在 uploadpath 下，阻止 ../ 逃逸\n        java.nio.file.Path root = Paths.get(uploadpath).toAbsolutePath().normalize();\n        SsrfFileTypeFilter.checkPathTraversal(fileRef);\n        String relativePath = fileRef.replaceAll(\"^[\\\\\\\\/]+\", \"\");\n        java.nio.file.Path target = root.resolve(relativePath).toAbsolutePath().normalize();\n        if (!target.startsWith(root)) {\n            log.error(\"检测到路径遍历攻击! fileRef: {}, 解析后: {}\", relativePath, target);\n            throw new JeecgBootException(\"文件路径包含非法字符\");\n        }\n        return target.toFile();\n        //update-end---author:wangshuai ---date:2026-04-13  for：【issues/9519】AI附件处理路径遍历漏洞：规范化路径并强制校验沙箱范围---\n    }\n    //================================================= end【QQYUN-14261】【AI】AI助手，支持多模态能力- 文档========================================\n\n\n    /**\n     * ai创作\n     *\n     * @param aiWriteGenerateVo\n     * @return\n     */\n    @Override\n    public SseEmitter genAiWriter(AiWriteGenerateVo aiWriteGenerateVo) {\n        String activeMode = \"compose\";\n        String reply = \"reply\";\n        ChatSendParams sendParams = new ChatSendParams();","sourceCodeStart":2179,"sourceCodeEnd":2215,"githubUrl":"https://github.com/jeecgboot/JeecgBoot/blob/96fb33f5ec68516da0b0147da06b2eb0419e063a/jeecg-boot/jeecg-boot-module/jeecg-boot-module-airag/src/main/java/org/jeecg/modules/airag/app/service/impl/AiragChatServiceImpl.java#L2179-L2215","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before (client) — sending a path with traversal characters\nString fileRef = \"../../uploads/document.pdf\";\n\n// after — sending a clean relative filename only\nString fileRef = \"document.pdf\";","handlingStrategy":"validation","validationCode":"// Server-side: validate fileRef before path resolution\npublic static boolean isSafeFileRef(String fileRef) {\n    if (fileRef == null || fileRef.isEmpty()) return false;\n    // Reject path traversal patterns\n    if (fileRef.contains(\"..\") || fileRef.contains(\"%2e%2e\")) return false;\n    // Reject absolute paths\n    if (fileRef.startsWith(\"/\") || fileRef.startsWith(\"\\\\\")) return false;\n    // Only allow alphanumeric, dash, underscore, dot, and standard separators\n    return fileRef.matches(\"[a-zA-Z0-9._\\\\-/]+\");\n}","typeGuard":"// Normalize and validate that resolved path stays within root\npublic static boolean isWithinUploadRoot(String uploadpath, String fileRef) {\n    try {\n        Path root = Paths.get(uploadpath).toAbsolutePath().normalize();\n        Path target = root.resolve(fileRef.replaceAll(\"^[\\\\\\\\/]+\", \"\")).toAbsolutePath().normalize();\n        return target.startsWith(root);\n    } catch (Exception e) {\n        return false;\n    }\n}","tryCatchPattern":"// This is a security guard — the exception should not be caught and suppressed.\n// Instead, log the security event and return an error to the client.\ntry {\n    File file = resolveAttachmentFile(fileRef, uploadpath);\n    // process file\n} catch (JeecgBootException e) {\n    if (e.getMessage().contains(\"非法字符\")) {\n        log.warn(\"[SECURITY] Path traversal attempt blocked: fileRef={}\", fileRef);\n        auditLogService.recordSecurityEvent(\"PATH_TRAVERSAL_ATTEMPT\", fileRef);\n    }\n    throw e;\n}","preventionTips":["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"],"tags":["security","path-traversal","cwe-22","airag","file-handling"],"backgroundTag":null,"analyzedSha":"96fb33f5ec68516da0b0147da06b2eb0419e063a","analyzedAt":"2026-08-14T00:04:16.786Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}