From 5cd5dc409bfc807f79dac5e4ef4aec54b6efd6e2 Mon Sep 17 00:00:00 2001 From: kolaente Date: Mon, 23 Mar 2026 21:18:23 +0100 Subject: [PATCH] fix: require admin access to list link shares Previously, any user with read access to a project could list all link shares including their hashes via GET /projects/{id}/shares. This allowed read-only collaborators to obtain write or admin link share hashes and escalate their privileges. Now ReadAll requires admin access to the project. --- pkg/models/link_sharing.go | 2 +- pkg/models/link_sharing_test.go | 26 ++++++++++++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/pkg/models/link_sharing.go b/pkg/models/link_sharing.go index 99bf7d118..a08b351bb 100644 --- a/pkg/models/link_sharing.go +++ b/pkg/models/link_sharing.go @@ -236,7 +236,7 @@ func (share *LinkSharing) ReadAll(s *xorm.Session, a web.Auth, search string, pa } project := &Project{ID: share.ProjectID} - can, _, err := project.CanRead(s, a) + can, err := project.IsAdmin(s, a) if err != nil { return nil, 0, 0, err } diff --git a/pkg/models/link_sharing_test.go b/pkg/models/link_sharing_test.go index 97748feef..268024e60 100644 --- a/pkg/models/link_sharing_test.go +++ b/pkg/models/link_sharing_test.go @@ -123,6 +123,32 @@ func TestLinkSharing_ReadAll(t *testing.T) { assert.Len(t, shares, 1) assert.Equal(t, int64(4), shares[0].ID) }) + t.Run("should forbid read-only users from listing link shares", func(t *testing.T) { + db.LoadAndAssertFixtures(t) + s := db.NewSession() + defer s.Close() + + // User 1 has only read access to project 3 + share := &LinkSharing{ + ProjectID: 3, + } + _, _, _, err := share.ReadAll(s, doer, "", 1, -1) + require.Error(t, err) + assert.True(t, IsErrGenericForbidden(err)) + }) + t.Run("should forbid write users from listing link shares", func(t *testing.T) { + db.LoadAndAssertFixtures(t) + s := db.NewSession() + defer s.Close() + + // User 1 has write access to project 10 + share := &LinkSharing{ + ProjectID: 10, + } + _, _, _, err := share.ReadAll(s, doer, "", 1, -1) + require.Error(t, err) + assert.True(t, IsErrGenericForbidden(err)) + }) } func TestLinkSharing_ReadOne(t *testing.T) {