MCPcopy Create free account
hub / github.com/Mnexa-AI/e2a / validateReturnToPath

Function validateReturnToPath

internal/auth/auth.go:307–340  ·  view source on GitHub ↗

validateReturnToPath enforces the same-origin / known-prefix allow-list for return_to values. Accepting an arbitrary URL would turn /api/auth/login into an open redirector that an attacker could chain with phishing-class social engineering. Limiting to /oauth2/-prefixed server paths means the bounce

(raw string)

Source from the content-addressed store, hash-verified

305// the bounce can only land inside the OAuth flow we own (Slice 5b renamed the
306// OAuth surface from /oauth2/* to /oauth2/*).
307func validateReturnToPath(raw string) error {
308 if !strings.HasPrefix(raw, "/oauth2/") {
309 return errors.New("return_to must be a server path starting with /oauth2/")
310 }
311 if strings.ContainsAny(raw, "\\\n\r\x00") {
312 return errors.New("return_to contains forbidden characters")
313 }
314 // url.Parse should produce a clean path-only URL: no scheme, no host.
315 u, err := url.Parse(raw)
316 if err != nil {
317 return errors.New("return_to is not a valid URL path")
318 }
319 if u.Scheme != "" || u.Host != "" || u.User != nil {
320 return errors.New("return_to must be a path with no scheme or authority")
321 }
322 // Reject path traversal that survives the HasPrefix check by being
323 // collapsed by the browser. e.g. raw "/oauth2/../../dashboard"
324 // matches the prefix but http.Redirect emits a Location header that
325 // the browser resolves to "/dashboard" — escaping the allow-list.
326 // path.Clean folds the "../" segments and we re-check the prefix on
327 // the normalized form.
328 cleaned := path.Clean(u.Path)
329 if !strings.HasPrefix(cleaned, "/oauth2/") && cleaned != "/oauth2" {
330 return errors.New("return_to escapes the allow-list after normalization")
331 }
332 // Also reject empty segments which a future router refactor might
333 // treat as authority. "/oauth2//foo" survives path.Clean as
334 // "/oauth2/foo" but the raw value carries the empty segment
335 // which some HTTP stacks parse differently — fail closed.
336 if strings.Contains(u.Path, "//") {
337 return errors.New("return_to must not contain empty path segments")
338 }
339 return nil
340}
341
342// HandleCallback processes the Google OAuth callback and creates a session.
343func (ua *UserAuth) HandleCallback(w http.ResponseWriter, r *http.Request) {

Callers 2

HandleLoginMethod · 0.85
HandleCallbackMethod · 0.85

Calls

no outgoing calls

Tested by

no test coverage detected