From 89e46bf539d865758e966054205f17c29da885ac Mon Sep 17 00:00:00 2001 From: Owen Rummage Date: Sat, 22 Aug 2026 23:45:39 -0500 Subject: [PATCH] Fix open-redirect via next parameter, remove dead code --- internal/web/auth_handlers.go | 5 +---- internal/web/playlists.go | 5 +---- internal/web/views.go | 8 -------- internal/web/web.go | 11 +++++++++++ 4 files changed, 13 insertions(+), 16 deletions(-) diff --git a/internal/web/auth_handlers.go b/internal/web/auth_handlers.go index bfbbdd8..716ce3c 100644 --- a/internal/web/auth_handlers.go +++ b/internal/web/auth_handlers.go @@ -47,10 +47,7 @@ func (h *Web) handleLogin(w http.ResponseWriter, r *http.Request) { } _ = database.TouchLastLogin(h.DB, user.ID) - if next == "" || next[0] != '/' { - next = "/" - } - http.Redirect(w, r, next, http.StatusFound) + http.Redirect(w, r, safeRedirectPath(next), http.StatusFound) } func (h *Web) loginFailed(w http.ResponseWriter, r *http.Request, next string) { diff --git a/internal/web/playlists.go b/internal/web/playlists.go index 8dc66bd..8ac8fdd 100644 --- a/internal/web/playlists.go +++ b/internal/web/playlists.go @@ -133,10 +133,7 @@ func (h *Web) setFavorite(w http.ResponseWriter, r *http.Request, star bool) { } itemType := r.FormValue("item_type") itemID := r.FormValue("item_id") - next := r.FormValue("next") - if next == "" || next[0] != '/' { - next = "/" - } + next := safeRedirectPath(r.FormValue("next")) switch itemType { case "song", "album", "artist": default: diff --git a/internal/web/views.go b/internal/web/views.go index 550c5df..9c9b074 100644 --- a/internal/web/views.go +++ b/internal/web/views.go @@ -2,7 +2,6 @@ package web import ( "database/sql" - "time" "git.noroutes.net/NoRoutes/vibetunes/internal/database" ) @@ -102,10 +101,3 @@ func albumOf(db *sql.DB, s *database.Song) *database.Album { } return album } - -type SessionView struct { - ID string - UserAgent string - IPAddress string - CreatedAt time.Time -} diff --git a/internal/web/web.go b/internal/web/web.go index 3ccb9d0..c72ac95 100644 --- a/internal/web/web.go +++ b/internal/web/web.go @@ -36,6 +36,17 @@ func (h *Web) page(w http.ResponseWriter, r *http.Request, name, active, title s }) } +// safeRedirectPath returns next if it's a same-site relative path, or +// "/" otherwise. Guards against open redirects: a bare "/foo" is fine, +// but "//evil.com" or "https://evil.com" are protocol-relative/absolute +// URLs a browser would follow off-site. +func safeRedirectPath(next string) string { + if next == "" || next[0] != '/' || len(next) > 1 && next[1] == '/' { + return "/" + } + return next +} + func (h *Web) flash(w http.ResponseWriter, r *http.Request, name, active, title, flash, kind string, data any) { render(w, name, PageData{ Active: active,