VYPR
Moderate severityOSV Advisory· Published Jan 8, 2026· Updated Jan 8, 2026

Soft Serve is missing an authorization check in LFS lock deletion

CVE-2026-22253

Description

Soft Serve is a self-hostable Git server for the command line. Prior to version 0.11.2, an authorization bypass in the LFS lock deletion endpoint allows any authenticated user with repository write access to delete locks owned by other users by setting the force flag. The vulnerable code path processes force deletions before retrieving user context, bypassing ownership validation entirely. This issue has been patched in version 0.11.2.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
github.com/charmbracelet/soft-serveGo
< 0.11.20.11.2

Affected products

1

Patches

1
000ab5164f0b

Merge commit from fork

https://github.com/charmbracelet/soft-serveTomer FichmanJan 8, 2026via ghsa
1 file changed · +21 11
  • pkg/web/git_lfs.go+21 11 modified
    @@ -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{
    

Vulnerability mechanics

Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

4

News mentions

0

No linked articles in our index yet.