Skip to content

Commit 801843b

Browse files
jonasfranzlunny
authored andcommitted
Fix open redirect vulnerability on login screen (#4312)
* Fix open redirect vulnerability on login screen Signed-off-by: Jonas Franz <[email protected]> * Reorder imports Signed-off-by: Jonas Franz <[email protected]> * Replace www. from Domain too Signed-off-by: Jonas Franz <[email protected]>
1 parent b8c2420 commit 801843b

File tree

3 files changed

+50
-1
lines changed

3 files changed

+50
-1
lines changed

modules/util/util.go

+13
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010
"strings"
1111

1212
"code.gitea.io/gitea/modules/log"
13+
"code.gitea.io/gitea/modules/setting"
1314
)
1415

1516
// OptionalBool a boolean that can be "null"
@@ -78,6 +79,18 @@ func URLJoin(base string, elems ...string) string {
7879
return joinedURL
7980
}
8081

82+
// IsExternalURL checks if rawURL points to an external URL like http://example.com
83+
func IsExternalURL(rawURL string) bool {
84+
parsed, err := url.Parse(rawURL)
85+
if err != nil {
86+
return true
87+
}
88+
if len(parsed.Host) != 0 && strings.Replace(parsed.Host, "www.", "", 1) != strings.Replace(setting.Domain, "www.", "", 1) {
89+
return true
90+
}
91+
return false
92+
}
93+
8194
// Min min of two ints
8295
func Min(a, b int) int {
8396
if a > b {

modules/util/util_test.go

+35
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ package util
77
import (
88
"testing"
99

10+
"code.gitea.io/gitea/modules/setting"
11+
1012
"github.com/stretchr/testify/assert"
1113
)
1214

@@ -42,3 +44,36 @@ func TestURLJoin(t *testing.T) {
4244
assert.Equal(t, test.Expected, URLJoin(test.Base, test.Elements...))
4345
}
4446
}
47+
48+
func TestIsExternalURL(t *testing.T) {
49+
setting.Domain = "try.gitea.io"
50+
type test struct {
51+
Expected bool
52+
RawURL string
53+
}
54+
newTest := func(expected bool, rawURL string) test {
55+
return test{Expected: expected, RawURL: rawURL}
56+
}
57+
for _, test := range []test{
58+
newTest(false,
59+
"https://try.gitea.io"),
60+
newTest(true,
61+
"https://example.com/"),
62+
newTest(true,
63+
"//example.com"),
64+
newTest(true,
65+
"http://example.com"),
66+
newTest(false,
67+
"a/"),
68+
newTest(false,
69+
"https://try.gitea.io/test?param=false"),
70+
newTest(false,
71+
"test?param=false"),
72+
newTest(false,
73+
"//try.gitea.io/test?param=false"),
74+
newTest(false,
75+
"/hey/hey/hey#3244"),
76+
} {
77+
assert.Equal(t, test.Expected, IsExternalURL(test.RawURL))
78+
}
79+
}

routers/user/auth.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import (
1818
"code.gitea.io/gitea/modules/context"
1919
"code.gitea.io/gitea/modules/log"
2020
"code.gitea.io/gitea/modules/setting"
21+
"code.gitea.io/gitea/modules/util"
2122

2223
"github.com/go-macaron/captcha"
2324
"github.com/markbates/goth"
@@ -474,7 +475,7 @@ func handleSignInFull(ctx *context.Context, u *models.User, remember bool, obeyR
474475
return setting.AppSubURL + "/"
475476
}
476477

477-
if redirectTo, _ := url.QueryUnescape(ctx.GetCookie("redirect_to")); len(redirectTo) > 0 {
478+
if redirectTo, _ := url.QueryUnescape(ctx.GetCookie("redirect_to")); len(redirectTo) > 0 && !util.IsExternalURL(redirectTo) {
478479
ctx.SetCookie("redirect_to", "", -1, setting.AppSubURL)
479480
if obeyRedirect {
480481
ctx.RedirectToFirst(redirectTo)

0 commit comments

Comments
 (0)