{"record":{"id":"6e35e269dd8fdb58","repo":"alibaba/spring-ai-alibaba","slug":"path-traversal-not-allowed-6e35e2","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/GrepSearchTool.java","lineNumber":260,"sourceCode":"\t\t\t\t}\n\t\t\t});\n\n\t\t\treturn results;\n\n\t\t} catch (Exception e) {\n\t\t\treturn Collections.emptyMap();\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 boolean isValidIncludePattern(String pattern) {\n\t\tif (pattern == null || pattern.isEmpty()) {\n\t\t\treturn false;\n\t\t}","sourceCodeStart":242,"sourceCodeEnd":278,"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/GrepSearchTool.java#L242-L278","documentation":"GrepSearchTool.validateAndResolvePath() performs the same guard as GlobSearchTool: any search path containing \"..\" or \"~\" raises IOException \"Path traversal not allowed\", preventing content searches outside the tool's root directory.","triggerScenarios":"The grep tool receives a path argument from the model or caller containing \"..\" or \"~\", e.g. searching \"~/.ssh\" or \"../../../etc\".","commonSituations":"LLM-generated regex/search calls with absolute home paths, prompt-injection exfiltration attempts, callers reusing paths from a differently-rooted tool.","solutions":["Normalize the path argument to a root-relative virtual path (starting with /) before calling.","Describe path constraints in the tool schema/description so the model stays within the root.","Catch the IOException and return an explanatory tool result so the model retries correctly.","Widen rootPath legitimately if users need access beyond the current root."],"exampleFix":"// before\ngrepTool.search(\"pattern\", \"~/notes\"); // IOException\n// after\ngrepTool.search(\"pattern\", \"/notes\");","handlingStrategy":"validation","validationCode":"if (path.contains(\"..\") || path.contains(\"~\")) { throw new IllegalArgumentException(\"use root-relative paths like /docs\"); }","typeGuard":"boolean isSafe(String p) { return p != null && !p.contains(\"..\") && !p.contains(\"~\"); }","tryCatchPattern":"try { tool.grep(pattern, path); } catch (IOException e) { if (e.getMessage().contains(\"Path traversal\")) { /* surface safe error to model */ } }","preventionTips":["Always pass root-relative virtual paths","Constrain the model via tool schema descriptions","Sanitize user-supplied search paths","Adjust rootPath rather than bypassing the guard"],"tags":["security","path-traversal","grep","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"}