{"record":{"id":"6f6ce0acb13c11eb","repo":"googleapis/mcp-toolbox","slug":"resolved-path-q-escapes-base-path-q","errorCode":null,"errorMessage":"resolved path %q escapes base path %q","messagePattern":"resolved path %q escapes base path %q","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/tools/http/http.go","lineNumber":223,"sourceCode":"\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\n\tqueryParameters := parsedURL.Query()\n\tfor key, value := range defaultQueryParams {\n\t\tqueryParameters.Add(key, value)\n\t}\n\tparsedURL.RawQuery = queryParameters.Encode()\n\n\t// Set dynamic query parameters\n\tquery := parsedURL.Query()\n\tfor _, p := range queryParams {\n\t\tv, ok := paramsMap[p.GetName()]\n\t\tif !ok || v == nil {\n\t\t\tif !p.GetRequired() {\n\t\t\t\t// If the param is not required AND\n\t\t\t\t// Not provodid OR provided with a nil value","sourceCodeStart":205,"sourceCodeEnd":241,"githubUrl":"https://github.com/googleapis/mcp-toolbox/blob/8cc6e09de2ad7b8bffc77751799585a1401a48eb/internal/tools/http/http.go#L205-L241","documentation":"Even after rejecting dot segments, the final URL (BaseURL resolved with the relative path) is checked to ensure its path stays within the base URL's path prefix. This error means the resolved path escaped the configured base path scope, so the request would target an endpoint outside what the tool was configured to allow.","triggerScenarios":"The base URL has a non-root path (e.g. https://host/api/v1) and the relative path resolves to something outside it — e.g. path '/other' resolves to https://host/other, or an encoded/absolute-style path replaces the base path during ResolveReference.","commonSituations":"Config authors set BaseURL including '/api/v1' but tool callers pass paths assuming the host root; paths beginning with '//' or containing encoded traversal slipping past earlier checks; misconfigured base path vs. documented API prefix mismatch.","solutions":["Make the relative path consistent with the base path prefix (e.g. pass '/items' to hit https://host/api/v1/items)","Fix the tool's BaseURL configuration so its path matches the actual API root the paths are written for","Inspect the resolved path in the error message and adjust it so it begins with the base path"],"exampleFix":"// before (base: https://host/api/v1)\npath: /other/endpoint\n// after\npath: /api-prefix-adjusted/endpoint  // or fix BaseURL to https://host/","handlingStrategy":"validation","validationCode":"base, _ := url.Parse(baseURL)\nrel, _ := url.Parse(pathParam)\nresolved := base.ResolveReference(rel)\nif !strings.HasPrefix(strings.TrimSuffix(base.Path, \"/\")+\"/\", resolved.Path) && resolved.Path != base.Path {\n    // only flag when resolved escapes; correct check:\n}\nrequired := strings.TrimSuffix(base.Path, \"/\") + \"/\"\nif resolved.Path != base.Path && !strings.HasPrefix(resolved.Path, required) {\n    return fmt.Errorf(\"path %q escapes base path %q\", resolved.Path, base.Path)\n}","typeGuard":"func staysWithinBase(baseURL, p string) bool {\n    base, _ := url.Parse(baseURL)\n    rel, err := url.Parse(p)\n    if err != nil { return false }\n    out := base.ResolveReference(rel)\n    required := strings.TrimSuffix(base.Path, \"/\") + \"/\"\n    return out.Path == base.Path || strings.HasPrefix(out.Path, required)\n}","tryCatchPattern":null,"preventionTips":["Author tool paths relative to the base URL's path prefix, not the host root","Mirror the API's documented prefix in BaseURL so paths like /items resolve correctly","Test each configured path template end-to-end against the base URL before deploying"],"tags":["http","url-validation","path-traversal","configuration"],"backgroundTag":"path-escapes-base-url","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"}