From 000ab5164f0be68cf1ea6b6e7227f11c0e388a42 Mon Sep 17 00:00:00 2001 From: Tomer Fichman Date: Thu, 8 Jan 2026 16:40:01 +0200 Subject: [PATCH] Merge commit from fork * fix: require admin privileges for force delete of LFS locks Move user context retrieval before the force flag check to ensure proper authorization. Force deletions now require admin privileges, preventing non-admin users from deleting locks owned by others. Fixes GHSA-6jm8-x3g6-r33j (CVE-2026-22253) Co-Authored-By: Claude Opus 4.5 * fix: improve comment clarity for force delete path Co-Authored-By: Claude Opus 4.5 --------- Co-authored-by: Claude Opus 4.5 --- pkg/web/git_lfs.go | 32 +++++++++++++++++++++----------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/pkg/web/git_lfs.go b/pkg/web/git_lfs.go index 72b37e88c9bd93773dd338bebceb2832a8f01b57..cc109107312891630b8f3c3884ec33bba9c0d2f9 100644 --- a/pkg/web/git_lfs.go +++ b/pkg/web/git_lfs.go @@ -893,7 +893,6 @@ func serviceLfsLocksDelete(w http.ResponseWriter, r *http.Request) { return } - // Delete another user's lock l := lfs.Lock{ ID: strconv.FormatInt(lock.ID, 10), Path: lock.Path, @@ -902,7 +901,27 @@ func serviceLfsLocksDelete(w http.ResponseWriter, r *http.Request) { Name: owner.Username, }, } + + // Retrieve user context first for authorization checks + user := proto.UserFromContext(ctx) + if user == nil { + logger.Error("error getting user from context") + renderJSON(w, http.StatusUnauthorized, lfs.ErrorResponse{ + Message: "unauthorized", + }) + return + } + + // Force delete another user's lock (requires admin privileges) if req.Force { + if !user.IsAdmin() { + logger.Error("non-admin user attempted force delete", "user", user.Username()) + renderJSON(w, http.StatusForbidden, lfs.ErrorResponse{ + Message: "admin access required for force delete", + }) + return + } + if err := datastore.DeleteLFSLock(ctx, dbx, repo.ID(), lockID); err != nil { logger.Error("error deleting lock", "err", err) renderJSON(w, http.StatusInternalServerError, lfs.ErrorResponse{ @@ -915,16 +934,7 @@ func serviceLfsLocksDelete(w http.ResponseWriter, r *http.Request) { return } - // Delete our own lock - user := proto.UserFromContext(ctx) - if user == nil { - logger.Error("error getting user from context") - renderJSON(w, http.StatusUnauthorized, lfs.ErrorResponse{ - Message: "unauthorized", - }) - return - } - + // Delete our own lock - verify ownership if owner.ID != user.ID() { logger.Error("error deleting another user's lock") renderJSON(w, http.StatusForbidden, lfs.ErrorResponse{