Skip to content
Open
12 changes: 9 additions & 3 deletions middleware/redirect.go
Original file line number Diff line number Diff line change
Expand Up @@ -180,9 +180,15 @@ func isValidRedirectHost(host string) bool {
if host == "" || host[0] == ':' || host[0] == '.' {
return false
}
// net/http validates Host syntax. Reject percent escapes too, since a
// browser could interpret them as authority delimiters in Location.
return !strings.Contains(host, "%")
// Reject control characters, authority/path delimiters, and percent escapes,
// since a browser could interpret them as authority delimiters in Location.
for i := 0; i < len(host); i++ {
ch := host[i]
if ch <= 0x20 || ch >= 0x7f || strings.IndexByte(`/\@?#%`, ch) != -1 {
return false
}
}
return true
}

var redirectHTTPS = func(scheme, host, uri string) (bool, string) {
Expand Down
11 changes: 10 additions & 1 deletion middleware/redirect_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -341,7 +341,16 @@ func TestRedirectMalformedHost(t *testing.T) {
for _, tc := range []struct {
host string
hasWWW bool
}{{"", false}, {"www.", true}, {"www.:80", true}, {"WWW.", true}, {":80", false}, {".example.com", false}, {"example.com%2fpath", false}} {
}{
{"", false},
{"www.", true},
{"www.:80", true},
{"WWW.", true},
{":80", false},
{".example.com", false},
{"example.com%2fpath", false},
{"attacker.com@labstack.com", false},
} {
for _, mw := range []struct {
name string
make func() echo.MiddlewareFunc
Expand Down
Loading