mirror of
https://github.com/TecharoHQ/anubis.git
synced 2026-04-12 03:28:45 +00:00
fix(lib): close open redirect when in subrequest mode
Closes GHSA-cf57-c578-7jvv Previously Anubis had an open redirect in subrequest auth mode due to an insufficent fix in GHSA-jhjj-2g64-px7c. This patch adds additional validation at several steps of the flow to prevent open redirects in subrequest auth mode as well as implements automated testing to prevent this from occuring in the future.
This commit is contained in:
31
lib/http.go
31
lib/http.go
@@ -296,6 +296,16 @@ func (s *Server) constructRedirectURL(r *http.Request) (string, error) {
|
||||
if proto == "" || host == "" || uri == "" {
|
||||
return "", errors.New(localizer.T("missing_required_forwarded_headers"))
|
||||
}
|
||||
|
||||
switch proto {
|
||||
case "http", "https":
|
||||
// allowed
|
||||
default:
|
||||
lg := internal.GetRequestLogger(s.logger, r)
|
||||
lg.Warn("invalid protocol in X-Forwarded-Proto", "proto", proto)
|
||||
return "", errors.New(localizer.T("invalid_redirect"))
|
||||
}
|
||||
|
||||
// Check if host is allowed in RedirectDomains (supports '*' via glob)
|
||||
if len(s.opts.RedirectDomains) > 0 && !matchRedirectDomain(s.opts.RedirectDomains, host) {
|
||||
lg := internal.GetRequestLogger(s.logger, r)
|
||||
@@ -369,16 +379,31 @@ func (s *Server) ServeHTTPNext(w http.ResponseWriter, r *http.Request) {
|
||||
localizer := localization.GetLocalizer(r)
|
||||
|
||||
redir := r.FormValue("redir")
|
||||
urlParsed, err := r.URL.Parse(redir)
|
||||
urlParsed, err := url.ParseRequestURI(redir)
|
||||
if err != nil {
|
||||
s.respondWithStatus(w, r, localizer.T("redirect_not_parseable"), makeCode(err), http.StatusBadRequest)
|
||||
// if ParseRequestURI fails, try as relative URL
|
||||
urlParsed, err = r.URL.Parse(redir)
|
||||
if err != nil {
|
||||
s.respondWithStatus(w, r, localizer.T("redirect_not_parseable"), makeCode(err), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// validate URL scheme to prevent javascript:, data:, file:, tel:, etc.
|
||||
switch urlParsed.Scheme {
|
||||
case "", "http", "https":
|
||||
// allowed: empty scheme means relative URL
|
||||
default:
|
||||
lg := internal.GetRequestLogger(s.logger, r)
|
||||
lg.Warn("XSS attempt blocked, invalid redirect scheme", "scheme", urlParsed.Scheme, "redir", redir)
|
||||
s.respondWithStatus(w, r, localizer.T("invalid_redirect"), "", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
hostNotAllowed := len(urlParsed.Host) > 0 &&
|
||||
len(s.opts.RedirectDomains) != 0 &&
|
||||
!matchRedirectDomain(s.opts.RedirectDomains, urlParsed.Host)
|
||||
hostMismatch := r.URL.Host != "" && urlParsed.Host != r.URL.Host
|
||||
hostMismatch := r.URL.Host != "" && urlParsed.Host != "" && urlParsed.Host != r.URL.Host
|
||||
|
||||
if hostNotAllowed || hostMismatch {
|
||||
lg := internal.GetRequestLogger(s.logger, r)
|
||||
|
||||
Reference in New Issue
Block a user