From 8095ac6233663400058113de10abda97db7e1dc7 Mon Sep 17 00:00:00 2001 From: Bryan Frimin Date: Tue, 31 Mar 2026 14:34:20 +0200 Subject: [PATCH] Validate session transfer redirect with saferedirect The session transfer handler was blindly redirecting to the continue URL from the signed token. Use saferedirect with a trust center domain check to prevent open redirects, and only trigger session transfer for known trust center custom domains instead of any non-base-URL host. Signed-off-by: Bryan Frimin --- pkg/server/api/connect/v1/oidc_handler.go | 2 +- pkg/server/api/trust/v1/resolver.go | 13 +++++++++++-- pkg/server/api/trust/v1/session_transfer_handler.go | 6 +++++- 3 files changed, 17 insertions(+), 4 deletions(-) diff --git a/pkg/server/api/connect/v1/oidc_handler.go b/pkg/server/api/connect/v1/oidc_handler.go index 579786a35..8e34cf462 100644 --- a/pkg/server/api/connect/v1/oidc_handler.go +++ b/pkg/server/api/connect/v1/oidc_handler.go @@ -176,7 +176,7 @@ func (h *OIDCHandler) buildSessionTransferURL(ctx context.Context, redirectURL s token, err := authn.SignSessionTransfer(sessionID, redirectURL, h.cookieSecret) if err != nil { - h.logger.Error("cannot sign session transfer token", log.Error(err)) + h.logger.ErrorCtx(ctx, "cannot sign session transfer token", log.Error(err)) return "", false } diff --git a/pkg/server/api/trust/v1/resolver.go b/pkg/server/api/trust/v1/resolver.go index f6bb6e8db..8a59d1ae7 100644 --- a/pkg/server/api/trust/v1/resolver.go +++ b/pkg/server/api/trust/v1/resolver.go @@ -32,6 +32,7 @@ package trust_v1 import ( "context" + "net/http" "time" "github.com/go-chi/chi/v5" @@ -84,8 +85,16 @@ func NewMux( r.Use(compliancepage.NewCompliancePagePresenceMiddleware()) - sessionTransferHandler := NewSessionTransferHandler(iamSvc, cookieConfig, logger) - r.Get("/session-transfer", sessionTransferHandler.ServeHTTP) + sessionTransferHandler := NewSessionTransferHandler( + iamSvc, + cookieConfig, + func(ctx context.Context, host string) bool { + _, err := trustSvc.GetByDomainName(ctx, host) + return err == nil + }, + logger, + ) + r.Method(http.MethodGet, "/session-transfer", sessionTransferHandler) r.Use(authn.NewSessionMiddleware(iamSvc, cookieConfig)) r.Use(compliancepage.NewMemberProvisioningMiddleware(trustSvc, logger)) diff --git a/pkg/server/api/trust/v1/session_transfer_handler.go b/pkg/server/api/trust/v1/session_transfer_handler.go index 70b41268b..d96e533dd 100644 --- a/pkg/server/api/trust/v1/session_transfer_handler.go +++ b/pkg/server/api/trust/v1/session_transfer_handler.go @@ -22,6 +22,7 @@ import ( "go.gearno.de/kit/log" "go.probo.inc/probo/pkg/gid" "go.probo.inc/probo/pkg/iam" + "go.probo.inc/probo/pkg/saferedirect" "go.probo.inc/probo/pkg/securecookie" "go.probo.inc/probo/pkg/server/api/authn" ) @@ -30,18 +31,21 @@ type SessionTransferHandler struct { iam *iam.Service sessionCookie *authn.Cookie cookieSecret string + safeRedirect *saferedirect.SafeRedirect logger *log.Logger } func NewSessionTransferHandler( iamSvc *iam.Service, cookieConfig securecookie.Config, + allowedHost saferedirect.AllowedHostFunc, logger *log.Logger, ) *SessionTransferHandler { return &SessionTransferHandler{ iam: iamSvc, sessionCookie: authn.NewCookie(&cookieConfig), cookieSecret: cookieConfig.Secret, + safeRedirect: saferedirect.New(allowedHost), logger: logger, } } @@ -82,5 +86,5 @@ func (h *SessionTransferHandler) ServeHTTP(w http.ResponseWriter, r *http.Reques h.sessionCookie.Set(w, session) - http.Redirect(w, r, continueURL, http.StatusFound) + h.safeRedirect.Redirect(w, r, continueURL, "/", http.StatusFound) }