Only @ was refused in the host of a /v1/image/ URL, so a ? written as %3F gave the host cdn.example.com?x=1, which Go's URL parser reads as cdn.example.com with a query: it passed the allowlist and each text after the ? was cached under keys of its own. The host must now be a host name or an IPv4 address (letters, digits, -, _ and .) or an IPv6 address in brackets, either one optionally followed by : and a port; anything else is refused with 400. An IPv6 address without brackets, which needed a signature, is refused too. Model: opus-5-5
This commit is contained in:
@@ -50,6 +50,12 @@ var sizeFormatRegex = regexp.MustCompile(
|
||||
// percentEscapeRegex matches one percent-escape, such as "%2e"
|
||||
var percentEscapeRegex = regexp.MustCompile(`%[0-9A-Fa-f]{2}`)
|
||||
|
||||
// hostRegex matches the host of an image URL: a host name or an IPv4 address
|
||||
// (letters, digits, "-", "_" and "."), or an IPv6 address in brackets, either
|
||||
// one optionally followed by ":" and a port, which may be empty
|
||||
var hostRegex = regexp.MustCompile(
|
||||
`^([A-Za-z0-9_.-]+|\[[0-9A-Fa-f:.]+\])(:[0-9]*)?$`)
|
||||
|
||||
// ParsedURL contains the parsed components of an image proxy URL.
|
||||
type ParsedURL struct {
|
||||
// Host is the source origin host (e.g., "cdn.example.com")
|
||||
@@ -141,10 +147,12 @@ func parseImageComponents(remainder string) (*ParsedURL, error) {
|
||||
return nil, ErrMissingHost
|
||||
}
|
||||
|
||||
// A URL reads what comes before "@" as a user name and password, and the
|
||||
// rest as the host
|
||||
if strings.Contains(host, "@") {
|
||||
return nil, fmt.Errorf("%w: %q holds @", ErrInvalidHost, host)
|
||||
// Go's URL parser, which the allowlist check and the fetcher use, reads a
|
||||
// host that hostRegex does not match as a different host, or refuses it:
|
||||
// what comes before an "@" is a user name and password, and what comes
|
||||
// after a "?" or "#" is a query or a fragment
|
||||
if !hostRegex.MatchString(host) {
|
||||
return nil, fmt.Errorf("%w: %q", ErrInvalidHost, host)
|
||||
}
|
||||
|
||||
// Host names do not depend on letter case, so the allowlist, the upstream
|
||||
|
||||
Reference in New Issue
Block a user