mirror of
https://github.com/coder/coder.git
synced 2026-09-24 15:04:27 +08:00
fix(coderd): harden oauth2 redirect validation (#27274)
Closes DEVEX-604 Hardens `redirect` URL handling in the OAuth2/OIDC/external-auth callback flows so redirects are always reduced to a safe, relative path local to the application. Previously a redirect value with an opaque scheme (e.g. `javascript:...`) or a path with multiple leading slashes (e.g. `///evil.com`) could survive sanitization mostly intact. Also de-duplicates the previously copy-pasted `uriFromURL` helper (now exported `httpmw.URIFromURL`) so there's a single implementation shared by `coderd/userauth.go`, `coderd/externalauth.go`, and `coderd/httpmw/oauth2.go`. <details> <summary>Context</summary> Addresses a low-severity finding reported via a pentest disclosure: the redirect sanitizer used `url.Parse(...).RequestURI()`, which doesn't reject non-hierarchical (opaque) URLs and doesn't collapse extra leading slashes, so crafted `redirect` values could partially survive sanitization. </details> This PR was authored by a Coder Agent on behalf of @aslilac.
This commit is contained in:
+1
-11
@@ -5,7 +5,6 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
|
||||
"github.com/sqlc-dev/pqtype"
|
||||
"golang.org/x/sync/errgroup"
|
||||
@@ -331,7 +330,7 @@ func (api *API) externalAuthCallback(externalAuthConfig *externalauth.Config) ht
|
||||
// FE know not to enter the authentication loop again, and instead display an error.
|
||||
redirect = fmt.Sprintf("/external-auth/%s?redirected=true", externalAuthConfig.ID)
|
||||
}
|
||||
redirect = uriFromURL(redirect)
|
||||
redirect = httpapi.SafeRedirectPath(redirect)
|
||||
http.Redirect(rw, r, redirect, http.StatusTemporaryRedirect)
|
||||
}
|
||||
}
|
||||
@@ -429,12 +428,3 @@ func ExternalAuthConfig(cfg *externalauth.Config) codersdk.ExternalAuthLinkProvi
|
||||
CodeChallengeMethodsSupported: slice.ToStrings(cfg.CodeChallengeMethodsSupported),
|
||||
}
|
||||
}
|
||||
|
||||
func uriFromURL(u string) string {
|
||||
uri, err := url.Parse(u)
|
||||
if err != nil {
|
||||
return "/"
|
||||
}
|
||||
|
||||
return uri.RequestURI()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user