{"record":{"id":"a4fee727418d0fbb","repo":"alibaba/spring-ai-alibaba","slug":"path-traversal-not-allowed-a4fee7","errorCode":null,"errorMessage":"Path traversal not allowed","messagePattern":"Path traversal not allowed","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"spring-ai-alibaba-agent-framework/src/main/java/com/alibaba/cloud/ai/graph/agent/extension/tools/filesystem/FileSystemTools.java","lineNumber":76,"sourceCode":"\t * \n\t * @param rootDir Optional root directory for file operations\n\t * @param virtualMode When true, treat incoming paths as virtual absolute paths under cwd\n\t * @param maxFileSizeMb Maximum file size in MB for reading operations\n\t */\n\tpublic FileSystemTools(String rootDir, boolean virtualMode, int maxFileSizeMb) {\n\t\tthis.cwd = rootDir != null ? Paths.get(rootDir).toAbsolutePath().normalize() : Paths.get(\"\").toAbsolutePath();\n\t\tthis.virtualMode = virtualMode;\n\t\tthis.maxFileSizeBytes = maxFileSizeMb * 1024L * 1024L;\n\t}\n\n\t/**\n\t * Resolve a file path with security checks.\n\t */\n\tprivate Path resolvePath(String key) throws IllegalArgumentException {\n\t\tif (virtualMode) {\n\t\t\tString vpath = key.startsWith(\"/\") ? key : \"/\" + key;\n\t\t\tif (vpath.contains(\"..\") || vpath.startsWith(\"~\")) {\n\t\t\t\tthrow new IllegalArgumentException(\"Path traversal not allowed\");\n\t\t\t}\n\t\t\tPath full = cwd.resolve(vpath.substring(1)).normalize();\n\t\t\tif (!full.startsWith(cwd)) {\n\t\t\t\tthrow new IllegalArgumentException(\"Path:\" + full + \" outside root directory: \" + cwd);\n\t\t\t}\n\t\t\treturn full;\n\t\t}\n\n\t\tPath path = Paths.get(key);\n\t\tif (path.isAbsolute()) {\n\t\t\treturn path;\n\t\t}\n\t\treturn cwd.resolve(path).normalize();\n\t}\n\n\t// @formatter:off\n\t@Tool(name = \"read_file\", description = \"\"\"\n\t\tReads a file from the filesystem. You can access any file directly by using this tool.","sourceCodeStart":58,"sourceCodeEnd":94,"githubUrl":"https://github.com/alibaba/spring-ai-alibaba/blob/f82da0b50f35744c13968191be2b1cd2452ef550/spring-ai-alibaba-agent-framework/src/main/java/com/alibaba/cloud/ai/graph/agent/extension/tools/filesystem/FileSystemTools.java#L58-L94","documentation":"FileSystemTools resolves every tool path through resolvePath, which applies security checks. In virtual mode, any path containing \"..\" or starting with \"~\" is rejected with \"Path traversal not allowed\" to prevent escaping the tool's root directory. This is an intentional security guard, not a bug.","triggerScenarios":"A filesystem tool call (read/write/ls/glob etc.) receives a key like \"../secret.txt\", \"a/../../etc/passwd\", or \"~/notes.md\" while running in virtualMode.","commonSituations":"An LLM-generated tool argument includes ../ to reach files outside its sandbox; shell-style ~ expansion assumed to work; path joins built from user input that weren't normalized before the tool call.","solutions":["Rewrite the requested path to be relative to the tool's root directory without .. segments (e.g., use \"docs/file.txt\" instead of \"../docs/file.txt\").","Normalize/resolve paths in your own code before invoking the tool and reject ones that escape the root.","Do not prefix paths with ~; pass absolute-from-root virtual paths like \"/home/user/file.txt\" if the virtual FS layout expects it."],"exampleFix":"// before\nString path = \"../../etc/passwd\"; // rejected: Path traversal not allowed\n// after\nString path = \"/etc/passwd\"; // only if inside the configured root; otherwise use a path within cwd, e.g. \"data/file.txt\"","handlingStrategy":"validation","validationCode":"String normalized = Paths.get(key).normalize().toString();\nif (normalized.contains(\"..\") || normalized.startsWith(\"~\")) {\n    throw new IllegalArgumentException(\"Refusing to use path outside sandbox: \" + key);\n}","typeGuard":"static boolean isSafePath(String key) {\n    String v = key.startsWith(\"/\") ? key : \"/\" + key;\n    return !v.contains(\"..\") && !v.startsWith(\"~\");\n}","tryCatchPattern":"try {\n    fsTool.read(path);\n} catch (IllegalArgumentException e) {\n    if (e.getMessage().contains(\"Path traversal\")) {\n        log.warn(\"Rejected unsafe path argument: {}\", path);\n    }\n}","preventionTips":["Sanitize LLM-generated tool arguments before invoking filesystem tools.","Always express paths relative to the tool root; never pass ../ or ~ forms.","Document the sandbox root to the model in its system prompt so it requests in-root paths."],"tags":["java","security","path-traversal","filesystem-tools"],"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"}