Description
The BuildPath function constructs an HTTP request path from a path template and a request message (msg). However, values extracted from the message fields are injected directly into the path template without any escaping.
While certain path templates (such as resource name patterns like {name=publishers/*/books/*}) are designed to accept and preserve forward slashes (/), the complete lack of escaping allows characters like ?, #, or spaces to break the URL structure.
Affected Code
The raw string returned from queryParams.Get(key) is substituted directly:
transport/http/path.go
path = pathTemplateParamRE.ReplaceAllStringFunc(pathTemplate, func(in string) string {
matches := pathTemplateParamRE.FindStringSubmatch(in)
key := matches[1]
pathParams[key] = struct{}{}
return queryParams.Get(key) // <--- Problem: Injected directly without validation/escaping
})
Technical Impact
If the fields in the request message contain specific special characters, it could lead to:
- URL Structure Corruption: Spaces or control characters causing malformed HTTP requests.
- Query/Fragment Injection: An attacker or unexpected data injecting a
? or # into the path segment, modifying query parameters or the URL fragment prematurely.
- Unintended Routing: Misrouting requests at the downstream service or reverse proxy level.
Suggested Fix Approach
Using standard url.PathEscape directly is incorrect because it breaks existing resource name patterns by escaping / into %2F.
Instead, the function should escape only the unsafe characters while preserving /. One common approach is to split the value by /, escape each segment individually using url.PathEscape, and then join them back together.
For example, a helper function could be used during substitution:
// Helper to escape path segments while preserving slashes for resource names
func escapePathValue(v string) string {
segments := strings.Split(v, "/")
for i, s := range segments {
segments[i] = url.PathEscape(s)
}
return strings.Join(segments, "/")
}
// Inside BuildPath:
path = pathTemplateParamRE.ReplaceAllStringFunc(pathTemplate, func(in string) string {
matches := pathTemplateParamRE.FindStringSubmatch(in)
key := matches[1]
pathParams[key] = struct{}{}
return escapePathValue(queryParams.Get(key)) // <--- Fix: Escape segments while keeping '/'
})
Description
The
BuildPathfunction constructs an HTTP request path from a path template and a request message (msg). However, values extracted from the message fields are injected directly into the path template without any escaping.While certain path templates (such as resource name patterns like
{name=publishers/*/books/*}) are designed to accept and preserve forward slashes (/), the complete lack of escaping allows characters like?,#, or spaces to break the URL structure.Affected Code
The raw string returned from
queryParams.Get(key)is substituted directly:transport/http/path.goTechnical Impact
If the fields in the request message contain specific special characters, it could lead to:
?or#into the path segment, modifying query parameters or the URL fragment prematurely.Suggested Fix Approach
Using standard
url.PathEscapedirectly is incorrect because it breaks existing resource name patterns by escaping/into%2F.Instead, the function should escape only the unsafe characters while preserving
/. One common approach is to split the value by/, escape each segment individually usingurl.PathEscape, and then join them back together.For example, a helper function could be used during substitution: