Security: Fixes for CVE-2025-6197 and CVE-2025-6023 (#108280)

fix(redirect): make validation of redirect uri stricter

Co-authored-by: volcanonoodle <114113189+volcanonoodle@users.noreply.github.com>
This commit is contained in:
Jev Forsberg
2025-07-17 15:06:45 -06:00
committed by GitHub
co-authored by volcanonoodle
parent 1e9c78656a
commit 988d964200
6 changed files with 147 additions and 11 deletions
+15
View File
@@ -3,6 +3,8 @@ package middleware
import (
"fmt"
"net/http"
"path"
"regexp"
"strconv"
"github.com/grafana/grafana/pkg/services/contexthandler"
@@ -11,6 +13,9 @@ import (
"github.com/grafana/grafana/pkg/web"
)
// Only allow redirects that start with an alphanumerical character, a dash or an underscore.
var redirectRe = regexp.MustCompile(`^/?[a-zA-Z0-9-_].*`)
// OrgRedirect changes org and redirects users if the
// querystring `orgId` doesn't match the active org.
func OrgRedirect(cfg *setting.Cfg, userSvc user.Service) web.Handler {
@@ -31,6 +36,11 @@ func OrgRedirect(cfg *setting.Cfg, userSvc user.Service) web.Handler {
return
}
if !validRedirectPath(c.Req.URL.Path) {
// Do not switch orgs or perform the redirect because the new path is not valid
return
}
if err := userSvc.Update(ctx.Req.Context(), &user.UpdateUserCommand{UserID: ctx.UserID, OrgID: &orgId}); err != nil {
if ctx.IsApiRequest() {
ctx.JsonApiErr(404, "Not found", nil)
@@ -54,3 +64,8 @@ func OrgRedirect(cfg *setting.Cfg, userSvc user.Service) web.Handler {
c.Redirect(newURL, 302)
}
}
func validRedirectPath(p string) bool {
cleanPath := path.Clean(p)
return cleanPath == "." || cleanPath == "/" || redirectRe.MatchString(cleanPath)
}
+17
View File
@@ -2,6 +2,7 @@ package middleware
import (
"fmt"
"net/url"
"testing"
"github.com/stretchr/testify/require"
@@ -23,6 +24,12 @@ func TestOrgRedirectMiddleware(t *testing.T) {
expStatus: 302,
expLocation: "/?orgId=3",
},
{
desc: "when setting a correct org for the user with an empty path",
input: "?orgId=3",
expStatus: 302,
expLocation: "/?orgId=3",
},
{
desc: "when setting a correct org for the user with '&kiosk'",
input: "/?orgId=3&kiosk",
@@ -64,6 +71,16 @@ func TestOrgRedirectMiddleware(t *testing.T) {
require.Equal(t, 404, sc.resp.Code)
})
middlewareScenario(t, "when redirecting to an invalid path", func(t *testing.T, sc *scenarioContext) {
sc.withIdentity(&authn.Identity{})
path := url.QueryEscape(`/\example.com`)
sc.m.Get(url.QueryEscape(path), sc.defaultHandler)
sc.fakeReq("GET", fmt.Sprintf("%s?orgId=3", path)).exec()
require.Equal(t, 404, sc.resp.Code)
})
middlewareScenario(t, "works correctly when grafana is served under a subpath", func(t *testing.T, sc *scenarioContext) {
sc.withIdentity(&authn.Identity{})