googleapis/mcp-toolbox · error

path must be relative and cannot override base host

Error message

path must be relative and cannot override base host

What it means

The HTTP tool resolves a user-supplied (templated) path against a fixed BaseURL. This library throws this error when the path is not purely relative — i.e. it contains a scheme (http://), a host, or userinfo — because letting the path override the base host would allow requests to arbitrary servers, breaking the tool's configured destination and enabling SSRF.

Solutions

  1. Pass only the relative path portion (e.g. '/v1/items?id=1') in the path parameter and keep the host in the tool's BaseURL configuration
  2. If a different host is needed, define a separate http tool source with that BaseURL instead of overriding the path
  3. Check the templated values being substituted into the path (custom functions/templates may inject a full URL); strip scheme+host before substitution

Example fix

// before
path: https://api.example.com/v1/items
// after
path: /v1/items
Defensive patterns

Strategy: validation

Validate before calling

u, err := url.Parse(pathParam)
if err != nil || u.Scheme != "" || u.Host != "" || u.User != nil {
    return fmt.Errorf("path must be relative: %q", pathParam)
}

Type guard

func isRelativePath(p string) bool {
    u, err := url.Parse(p)
    return err == nil && u.Scheme == "" && u.Host == "" && u.User == nil
}

Prevention

When it happens

Trigger: getURL is called (via Invoke) with a Path parameter that parses as an absolute URL, e.g. the caller passes 'https://evil.example.com/api' or '//evil.example.com/api' or 'user@host/path' as the templated path instead of a relative path like '/api/items'.

Common situations: Developers template the full URL into the path parameter because the model or client handed them a complete URL; config authors define an http tool whose base URL already includes a suffix path and then pass an absolute URL hoping to change hosts; SSRF-probe requests attempting host override.

Related errors


AI-assisted analysis of googleapis/mcp-toolbox@8cc6e09de2 (2026-09-05). Data as JSON: /api/errors/8225012523708a6c. Report an issue: GitHub.

Appendix: source

Thrown at internal/tools/http/http.go:203

	if err != nil {
		return "", fmt.Errorf("error replacing pathParams: %s", err)
	}

	baseParsedURL, err := url.Parse(baseURL)
	if err != nil {
		return "", fmt.Errorf("error parsing base URL: %s", err)
	}
	if baseParsedURL.Scheme == "" || baseParsedURL.Host == "" {
		return "", fmt.Errorf("base URL must include scheme and host")
	}

	relativePath := templatedPath.String()
	relParsedURL, err := url.Parse(relativePath)
	if err != nil {
		return "", fmt.Errorf("error parsing URL path: %s", err)
	}
	if relParsedURL.Scheme != "" || relParsedURL.Host != "" || relParsedURL.User != nil {
		return "", fmt.Errorf("path must be relative and cannot override base host")
	}

	// Reject dot segments before resolution
	for _, segment := range strings.Split(relParsedURL.Path, "/") {
		if segment == ".." {
			return "", fmt.Errorf("path cannot contain dot segments (..)")
		}
	}

	// Create URL based on BaseURL and Path
	// Attach query parameters
	parsedURL := baseParsedURL.ResolveReference(relParsedURL)

	// Verify final path stays within base path scope
	basePath := baseParsedURL.Path
	finalPath := parsedURL.Path
	if basePath != "/" {
		requiredPrefix := strings.TrimSuffix(basePath, "/") + "/"

View on GitHub (pinned to 8cc6e09de2)