{"record":{"id":"d6e512840a330bc0","repo":"googleapis/mcp-toolbox","slug":"path-cannot-contain-dot-segments","errorCode":null,"errorMessage":"path cannot contain dot segments (..)","messagePattern":"path cannot contain dot segments \\(\\.\\.\\)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/tools/http/http.go","lineNumber":209,"sourceCode":"\t\treturn \"\", fmt.Errorf(\"error parsing base URL: %s\", err)\n\t}\n\tif baseParsedURL.Scheme == \"\" || baseParsedURL.Host == \"\" {\n\t\treturn \"\", fmt.Errorf(\"base URL must include scheme and host\")\n\t}\n\n\trelativePath := templatedPath.String()\n\trelParsedURL, err := url.Parse(relativePath)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"error parsing URL path: %s\", err)\n\t}\n\tif relParsedURL.Scheme != \"\" || relParsedURL.Host != \"\" || relParsedURL.User != nil {\n\t\treturn \"\", fmt.Errorf(\"path must be relative and cannot override base host\")\n\t}\n\n\t// Reject dot segments before resolution\n\tfor _, segment := range strings.Split(relParsedURL.Path, \"/\") {\n\t\tif segment == \"..\" {\n\t\t\treturn \"\", fmt.Errorf(\"path cannot contain dot segments (..)\")\n\t\t}\n\t}\n\n\t// Create URL based on BaseURL and Path\n\t// Attach query parameters\n\tparsedURL := baseParsedURL.ResolveReference(relParsedURL)\n\n\t// Verify final path stays within base path scope\n\tbasePath := baseParsedURL.Path\n\tfinalPath := parsedURL.Path\n\tif basePath != \"/\" {\n\t\trequiredPrefix := strings.TrimSuffix(basePath, \"/\") + \"/\"\n\t\tif finalPath != basePath && !strings.HasPrefix(finalPath, requiredPrefix) {\n\t\t\treturn \"\", fmt.Errorf(\"resolved path %q escapes base path %q\", finalPath, basePath)\n\t\t}\n\t}\n\n\t// Get existing query parameters from the URL","sourceCodeStart":191,"sourceCodeEnd":227,"githubUrl":"https://github.com/googleapis/mcp-toolbox/blob/8cc6e09de2ad7b8bffc77751799585a1401a48eb/internal/tools/http/http.go#L191-L227","documentation":"After parsing the relative path, getURL rejects any path segment equal to '..' before resolving against the BaseURL. Dot segments could make the resolved URL climb out of the configured base path scope, so they are refused outright as a path-traversal defense.","triggerScenarios":"getURL is called with a path containing a literal '..' segment such as '/v1/../admin' or '/files/../../etc' — typically produced by user/model-supplied path parameters or naive path joins.","commonSituations":"LLM-generated tool arguments containing '..'; clients attempting to escape a restricted API prefix; accidental double-resolution where a caller pre-joins paths with '..' to 'go up' a level.","solutions":["Remove '..' segments from the path and specify the full intended path from the base (e.g. use '/admin' instead of '/v1/../admin')","Normalize/resolve the desired path client-side before passing it, so only a clean absolute-relative path reaches the tool","If traversal out of the base path is genuinely required, configure the tool's BaseURL at the higher-level path"],"exampleFix":"// before\npath: /v1/../admin/settings\n// after\npath: /admin/settings","handlingStrategy":"validation","validationCode":"for _, seg := range strings.Split(pathParam, \"/\") {\n    if seg == \"..\" {\n        return fmt.Errorf(\"dot segments not allowed in path: %q\", pathParam)\n    }\n}","typeGuard":"func hasDotSegments(p string) bool {\n    for _, seg := range strings.Split(p, \"/\") {\n        if seg == \"..\" { return true }\n    }\n    return false\n}","tryCatchPattern":null,"preventionTips":["Strip and resolve '..' segments before passing paths to the tool","Constrain LLM/tool callers to a fixed allowlist of path templates","Log and reject any user input containing '..' at the application boundary"],"tags":["http","path-traversal","url-validation","security"],"backgroundTag":"path-traversal-rejected","analyzedSha":"8cc6e09de2ad7b8bffc77751799585a1401a48eb","analyzedAt":"2026-09-05T01:10:36.887Z","contentChangedAt":"2026-09-05T01:10:36.887Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}