{"record":{"id":"9cb4cc3d14e9ddaf","repo":"Tencent/WeKnora","slug":"command-path-contains-invalid-characters","errorCode":null,"errorMessage":"command path contains invalid characters","messagePattern":"command path contains invalid characters","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/utils/security.go","lineNumber":552,"sourceCode":"\tif command == \"\" {\n\t\treturn fmt.Errorf(\"command cannot be empty\")\n\t}\n\n\t// Normalize command (extract base name if it's a path)\n\tbaseCommand := command\n\tif strings.Contains(command, \"/\") {\n\t\tparts := strings.Split(command, \"/\")\n\t\tbaseCommand = parts[len(parts)-1]\n\t}\n\n\t// Check against whitelist\n\tif !AllowedStdioCommands[baseCommand] {\n\t\treturn fmt.Errorf(\"command '%s' is not in the allowed list. Allowed commands: uvx, npx, node, python, python3, deno, bun\", baseCommand)\n\t}\n\n\t// Additional check: command should not contain path traversal\n\tif strings.Contains(command, \"..\") {\n\t\treturn fmt.Errorf(\"command path contains invalid characters\")\n\t}\n\n\treturn nil\n}\n\n// ValidateStdioArgs validates the arguments for MCP stdio transport\n// Returns an error if any argument contains dangerous patterns\nfunc ValidateStdioArgs(args []string) error {\n\tif len(args) == 0 {\n\t\treturn nil\n\t}\n\n\tfor i, arg := range args {\n\t\t// Check length\n\t\tif len(arg) > 1024 {\n\t\t\treturn fmt.Errorf(\"argument %d exceeds maximum length (1024 characters)\", i)\n\t\t}\n","sourceCodeStart":534,"sourceCodeEnd":570,"githubUrl":"https://github.com/Tencent/WeKnora/blob/988cbb03305e055d8ebb7d46d9ac6cc0803cd074/internal/utils/security.go#L534-L570","documentation":"After passing the whitelist, ValidateStdioCommand performs a final check that the raw command string contains no \"..\" path-traversal segments. This blocks tricks where a whitelisted base name is embedded in a traversal path. The error text is generic (\"invalid characters\") but specifically means \"..\" was found.","triggerScenarios":"ValidateStdioConfig called with a command such as \"../node\", \"npx/../node\", or any string containing \"..\" whose base name still matches the whitelist.","commonSituations":"Relative paths written from a config directory; hand-built command strings joining directories with \"..\"; copy-pasted paths from shell history with dot-dot segments.","solutions":["Remove \"..\" from the command path; use an absolute path whose base name is whitelisted (e.g. /usr/bin/node) or just the bare command name and rely on PATH","Use path.Clean/filepath.Clean to normalize the path and confirm no \"..\" remains","Prefer launching via the bare command name (\"node\") so the OS PATH resolution is used"],"exampleFix":"// before\n{\"command\": \"../bin/node\", \"args\": [\"server.js\"]}\n// after\n{\"command\": \"node\", \"args\": [\"server.js\"]}","handlingStrategy":"validation","validationCode":"if strings.Contains(cfg.Command, \"..\") {\n    return fmt.Errorf(\"command path must not contain '..'\")\n}\nerr := ValidateStdioConfig(cfg)","typeGuard":null,"tryCatchPattern":"if err := ValidateStdioConfig(cfg); err != nil {\n    if strings.Contains(err.Error(), \"invalid characters\") {\n        return fmt.Errorf(\"command %q contains traversal segments; use bare name or absolute path\", cfg.Command)\n    }\n    return err\n}","preventionTips":["Use bare command names and PATH resolution instead of relative paths","Normalize any path with filepath.Clean before validation","Reject '..' in all executable paths at config-parse time"],"tags":["security","path-traversal","mcp","stdio"],"backgroundTag":"path-traversal-detected","analyzedSha":"988cbb03305e055d8ebb7d46d9ac6cc0803cd074","analyzedAt":"2026-09-02T14:41:08.344Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T15:18:49.778Z"}