diff --git a/internal/utilities/request.go b/internal/utilities/request.go index bfe0a51df1..8a2d336cb5 100644 --- a/internal/utilities/request.go +++ b/internal/utilities/request.go @@ -6,6 +6,7 @@ import ( "net" "net/http" "net/url" + "regexp" "strings" "github.com/supabase/auth/internal/conf" @@ -79,6 +80,8 @@ func GetReferrer(r *http.Request, config *conf.GlobalConfiguration) string { return config.SiteURL } +var decimalIPAddressPattern = regexp.MustCompile("^[0-9]+$") + func IsRedirectURLValid(config *conf.GlobalConfiguration, redirectURL string) bool { if redirectURL == "" { return false @@ -92,9 +95,17 @@ func IsRedirectURLValid(config *conf.GlobalConfiguration, redirectURL string) bo return true } - // Clean up the referrer URL to avoid pattern matching an invalid URL - refurl.Fragment = "" - refurl.RawQuery = "" + if rerr != nil { + // redirect URL is for some reason invalid + return false + } + + if decimalIPAddressPattern.MatchString(refurl.Hostname()) { + // IP address in decimal form also not allowed in redirects! + return false + } else if ip := net.ParseIP(refurl.Hostname()); ip != nil { + return ip.IsLoopback() + } // For case when user came from mobile app or other permitted resource - redirect back for _, pattern := range config.URIAllowListMap { diff --git a/internal/utilities/request_test.go b/internal/utilities/request_test.go index d08e86ae66..c1d1a66219 100644 --- a/internal/utilities/request_test.go +++ b/internal/utilities/request_test.go @@ -91,7 +91,7 @@ func TestGetIPAddress(t *tst.T) { func TestGetReferrer(t *tst.T) { config := conf.GlobalConfiguration{ SiteURL: "https://example.com", - URIAllowList: []string{"http://localhost:8000/*", "http://*.localhost:8000/*"}, + URIAllowList: []string{"http://localhost:8000/*", "http://*.localhost:8000/*", "http://*:12345/*", "http://**:12345/*"}, JWT: conf.JWTConfiguration{ Secret: "testsecret", }, @@ -128,10 +128,35 @@ func TestGetReferrer(t *tst.T) { expected: "http://localhost:8000/path?param=1", }, { - desc: "invalid redirect url via query smurfing", + desc: "invalid redirect url due to decimal IP address", redirectURL: "http://123?.localhost:8000/path", expected: config.SiteURL, }, + { + desc: "invalid redirect url due to IPv4 address", + redirectURL: "http://123.123.123.123?localhost:8000/path", + expected: config.SiteURL, + }, + { + desc: "invalid redirect url due to IPv6 address", + redirectURL: "http://[65e7:9410:d8b6:e227:58cd:e55b:8fc0:206d]?localhost:8000/path", + expected: config.SiteURL, + }, + { + desc: "invalid redirect url due to bad URL", + redirectURL: "http://65e7:9410:d8b6:e227:58cd:e55b:8fc0:206d?localhost:8000/path", + expected: config.SiteURL, + }, + { + desc: "valid loopback IPv4 address", + redirectURL: "http://127.0.0.1:12345/path", + expected: "http://127.0.0.1:12345/path", + }, + { + desc: "valid loopback IPv6 address", + redirectURL: "http://[0:0:0:0:0:0:0:1]:12345/path", + expected: "http://[0:0:0:0:0:0:0:1]:12345/path", + }, } for _, c := range cases {