{"record":{"id":"6200480c4c597cbf","repo":"alibaba/spring-ai-alibaba","slug":"path-traversal-not-allowed-620048","errorCode":null,"errorMessage":"Path traversal not allowed","messagePattern":"Path traversal not allowed","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"warning","filePath":"spring-ai-alibaba-agent-framework/src/main/java/com/alibaba/cloud/ai/graph/agent/tools/GlobSearchTool.java","lineNumber":169,"sourceCode":"\t\t\treturn \"Error: Invalid glob pattern syntax - \" + e.getDescription();\n\t\t} catch (InvalidPathException e) {\n\t\t\treturn \"Error: Invalid path format - \" + e.getReason();\n\t\t} catch (IOException e) {\n\t\t\treturn \"Error: I/O error - \" + e.getMessage();\n\t\t} catch (Exception e) {\n\t\t\treturn \"Error: Unexpected error occurred - \" + e.getMessage();\n\t\t}\n\t}\n\n\tprivate Path validateAndResolvePath(String path) throws IOException {\n\t\t// Normalize path\n\t\tif (!path.startsWith(\"/\")) {\n\t\t\tpath = \"/\" + path;\n\t\t}\n\n\t\t// Check for path traversal\n\t\tif (path.contains(\"..\") || path.contains(\"~\")) {\n\t\t\tthrow new IOException(\"Path traversal not allowed\");\n\t\t}\n\n\t\t// Convert virtual path to filesystem path\n\t\tString relative = path.substring(1); // Remove leading /\n\t\tPath fullPath = rootPath.resolve(relative).normalize();\n\n\t\t// Ensure path is within root\n\t\tif (!fullPath.startsWith(rootPath)) {\n\t\t\tthrow new IOException(\"Path outside root directory: \" + path);\n\t\t}\n\n\t\treturn fullPath;\n\t}\n\n\tprivate record FileInfo(String path, Instant modifiedTime) {}\n\n\tpublic static Builder builder(String rootPath) {\n\t\treturn new Builder(rootPath);","sourceCodeStart":151,"sourceCodeEnd":187,"githubUrl":"https://github.com/alibaba/spring-ai-alibaba/blob/f82da0b50f35744c13968191be2b1cd2452ef550/spring-ai-alibaba-agent-framework/src/main/java/com/alibaba/cloud/ai/graph/agent/tools/GlobSearchTool.java#L151-L187","documentation":"GlobSearchTool.validateAndResolvePath() rejects any virtual path containing \"..\" or \"~\" with IOException \"Path traversal not allowed\". This is a deliberate security guard so file-search tools can never escape the configured root directory.","triggerScenarios":"A tool call (often generated by the LLM) supplies a path like \"../../etc/passwd\" or \"~/secrets\" to the glob search tool's path argument.","commonSituations":"Model hallucinating relative parent paths, users pasting absolute home-directory paths, prompt-injection attempts trying to read files outside the workspace.","solutions":["Sanitize the requested path before calling the tool: strip .., ~ and make it root-relative.","Constrain the model via prompt/tool description to only use paths under the workspace root.","Catch IOException and return a safe tool error so the model can retry with a valid path.","If legitimate external access is needed, reconfigure the tool's rootPath instead of bypassing the check."],"exampleFix":"// before\nString userPath = \"../../etc/passwd\";\ntool.search(userPath); // IOException\n// after\nString safe = userPath.replace(\"..\", \"\").replace(\"~\", \"\");\ntool.search(safe.startsWith(\"/\") ? safe : \"/\" + safe);","handlingStrategy":"validation","validationCode":"function safePath(String p) { if (p.contains(\"..\") || p.contains(\"~\")) throw new IllegalArgumentException(\"path must stay in workspace\"); return p.startsWith(\"/\") ? p : \"/\" + p; }","typeGuard":"boolean isSafe(String p) { return p != null && !p.contains(\"..\") && !p.contains(\"~\"); }","tryCatchPattern":"try { tool.glob(pattern, path); } catch (IOException e) { if (e.getMessage().contains(\"Path traversal\")) { /* return safe error to model */ } }","preventionTips":["Sanitize model-supplied paths before tool calls","Document root-relative path format in tool descriptions","Never weaken the traversal check","Return informative errors so the model can self-correct"],"tags":["security","path-traversal","file-search","validation"],"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"}