{"record":{"id":"d58040adb9b3f05d","repo":"alibaba/spring-ai-alibaba","slug":"path","errorCode":null,"errorMessage":"非法路径访问尝试: ${path}","messagePattern":"非法路径访问尝试: (.+?)","errorType":"exception","errorClass":"SecurityException","httpStatus":null,"severity":"warning","filePath":"spring-ai-alibaba-admin/spring-ai-alibaba-admin-server-start/src/main/java/com/alibaba/cloud/ai/studio/admin/builder/generator/service/generator/workflow/sections/KnowledgeRetrievalNodeSection.java","lineNumber":102,"sourceCode":"\t\t\t\t})\n\t\t\t\t.flatMap(List::stream)\n\t\t\t\t.filter(Document::getEnabled)\n\t\t\t\t.filter(d -> StringUtils.hasText(d.getPath()))\n\t\t\t\t.map(document -> {\n\t\t\t\t\t// 文件类型\n\t\t\t\t\tString contentType = document.getMetadata().getContentType();\n\t\t\t\t\t// 存储形式\n\t\t\t\t\tDocumentType documentType = document.getType();\n\t\t\t\t\t// 存储路径\n\t\t\t\t\tString path = switch (documentType) {\n\t\t\t\t\t\tcase FILE -> {\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tPath p = Path.of(studioStoragePath);\n\t\t\t\t\t\t\t\tPath resolvedPath = p.resolve(document.getPath()).normalize();\n\n\t\t\t\t\t\t\t\t// 安全检查：确保解析后的路径仍在允许的目录范围内\n\t\t\t\t\t\t\t\tif (!resolvedPath.startsWith(p.normalize())) {\n\t\t\t\t\t\t\t\t\tthrow new SecurityException(\"非法路径访问尝试: \" + document.getPath());\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\tyield resolvedPath.toAbsolutePath().toString();\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tcase URL -> {\n\t\t\t\t\t\t\t// 对URL路径进行基本验证\n\t\t\t\t\t\t\tString urlPath = document.getPath();\n\t\t\t\t\t\t\tif (urlPath == null || urlPath.trim().isEmpty()) {\n\t\t\t\t\t\t\t\tthrow new IllegalArgumentException(\"URL路径不能为空\");\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tyield urlPath;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tdefault ->\n\t\t\t\t\t\t\tthrow new UnsupportedOperationException(\"unsupported document type: \" + documentType);\n\t\t\t\t\t};\n\t\t\t\t\tString fileName = document.getName();\n\t\t\t\t\t// 构造文件记录","sourceCodeStart":84,"sourceCodeEnd":120,"githubUrl":"https://github.com/alibaba/spring-ai-alibaba/blob/f82da0b50f35744c13968191be2b1cd2452ef550/spring-ai-alibaba-admin/spring-ai-alibaba-admin-server-start/src/main/java/com/alibaba/cloud/ai/studio/admin/builder/generator/service/generator/workflow/sections/KnowledgeRetrievalNodeSection.java#L84-L120","documentation":"During Studio knowledge retrieval code generation, each document's relative path is resolved against studioStoragePath and normalized; if the resolved path escapes the storage root (classic ../ traversal), a SecurityException('非法路径访问尝试: <path>') is thrown. This is a deliberate path-traversal guard protecting files outside the allowed document directory.","triggerScenarios":"render() on a STUDIO knowledge retrieval node where a ResourceFile's path contains '..' or absolute components such that p.resolve(path).normalize() no longer starts with the normalized storage root.","commonSituations":"A malicious or corrupted imported workflow references document paths like '../../etc/passwd'; database rows for document paths were edited by hand; symlinks/absolute paths in stored document metadata.","solutions":["Fix the document.getPath() value in the knowledge base record so it is a plain relative path under the storage root.","Re-import the workflow from a trusted source; sanitize imported document paths (strip leading '/', '..' segments).","Verify studioStoragePath is the intended root — a wrong root can make legitimate relative paths appear to escape."],"exampleFix":"// before\ndocument.path = \"../../etc/passwd\"\n// after\ndocument.path = \"docs/manual.pdf\"  // relative, within studioStoragePath","handlingStrategy":"validation","validationCode":"Path root = Path.of(studioStoragePath).normalize();\nPath resolved = root.resolve(doc.getPath()).normalize();\nif (!resolved.startsWith(root)) throw new SecurityException(\"Blocked path traversal: \" + doc.getPath());","typeGuard":"boolean isInsideStorage(Path root, String relative) { return root.resolve(relative).normalize().startsWith(root.normalize()); }","tryCatchPattern":"try { generator.generate(spec); } catch (SecurityException e) { log.warn(\"Rejected unsafe document path: {}\", e.getMessage()); /* skip or fix the document record */ }","preventionTips":["Store only plain relative paths in document records; sanitize on import","Never allow user-editable absolute paths or '..' segments in knowledge base documents","Keep the traversal guard in place and log rejected paths for auditing"],"tags":["security","path-traversal","knowledge-retrieval"],"backgroundTag":"path-traversal-blocked","analyzedSha":"f82da0b50f35744c13968191be2b1cd2452ef550","analyzedAt":"2026-09-09T15:32:42.421Z","contentChangedAt":"2026-09-09T15:32:42.421Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}