From 8cf0f9798f0b93b85ecf9b38c2af25bd4d9898ad Mon Sep 17 00:00:00 2001 From: silverwind Date: Thu, 29 Oct 2026 11:04:51 +0100 Subject: [PATCH] fix(feed): require code read access for the repo home branch feed (#39964) (#40067) Backport https://github.com/go-gitea/gitea/pull/39964 The repo home URL served the branch or file commit feed for RSS or Atom `Accept` headers without the code unit check of the explicit `/rss/branch/*` routes, exposing commit messages and authors to users without code access. Co-authored-by: Basavaraj S m --- routers/web/feed/branch.go | 3 +-- routers/web/feed/file.go | 3 +-- routers/web/feed/render.go | 4 ++-- routers/web/repo/view_home.go | 8 +++++--- tests/integration/feed_repo_test.go | 10 ++++++++++ 5 files changed, 19 insertions(+), 9 deletions(-) diff --git a/routers/web/feed/branch.go b/routers/web/feed/branch.go index 76184d64438..6793bb6a695 100644 --- a/routers/web/feed/branch.go +++ b/routers/web/feed/branch.go @@ -13,8 +13,7 @@ import ( "github.com/gorilla/feeds" ) -// ShowBranchFeed shows tags and/or releases on the repo as RSS / Atom feed -func ShowBranchFeed(ctx *context.Context, repo *repo.Repository, formatType string) { +func showBranchFeed(ctx *context.Context, repo *repo.Repository, formatType string) { if !checkRepoFeedTokenScope(ctx) { return } diff --git a/routers/web/feed/file.go b/routers/web/feed/file.go index debb6dd4c9c..9ea35a796cc 100644 --- a/routers/web/feed/file.go +++ b/routers/web/feed/file.go @@ -14,8 +14,7 @@ import ( "github.com/gorilla/feeds" ) -// ShowFileFeed shows tags and/or releases on the repo as RSS / Atom feed -func ShowFileFeed(ctx *context.Context, repo *repo.Repository, formatType string) { +func showFileFeed(ctx *context.Context, repo *repo.Repository, formatType string) { if !checkRepoFeedTokenScope(ctx) { return } diff --git a/routers/web/feed/render.go b/routers/web/feed/render.go index d06aa22e64c..1ffa10a7a2f 100644 --- a/routers/web/feed/render.go +++ b/routers/web/feed/render.go @@ -19,9 +19,9 @@ func checkRepoFeedTokenScope(ctx *context.Context) bool { // RenderBranchFeed render format for branch or file func RenderBranchFeed(ctx *context.Context, feedType string) { if ctx.Repo.TreePath == "" { - ShowBranchFeed(ctx, ctx.Repo.Repository, feedType) + showBranchFeed(ctx, ctx.Repo.Repository, feedType) } else { - ShowFileFeed(ctx, ctx.Repo.Repository, feedType) + showFileFeed(ctx, ctx.Repo.Repository, feedType) } } diff --git a/routers/web/repo/view_home.go b/routers/web/repo/view_home.go index a5721760828..67b2335a7f8 100644 --- a/routers/web/repo/view_home.go +++ b/routers/web/repo/view_home.go @@ -333,10 +333,12 @@ func handleRepoHomeFeed(ctx *context.Context) bool { } if ctx.Link == fmt.Sprintf("%s.%s", ctx.Repo.RepoLink, showFeedType) { feed.ShowRepoFeed(ctx, ctx.Repo.Repository, showFeedType) - } else if ctx.Repo.TreePath == "" { - feed.ShowBranchFeed(ctx, ctx.Repo.Repository, showFeedType) + } else if !ctx.Repo.Permission.CanRead(unit_model.TypeCode) && !ctx.Repo.CanWriteToBranch(ctx, ctx.Doer, ctx.Repo.BranchName) { + // the branch and file feeds list commits, so gate them like RequireUnitReader(TypeCode) on "/rss/branch/*", + // which also admits maintainers of a PR allowing maintainer edits, who can push to its head branch without code read access + ctx.NotFound(nil) } else { - feed.ShowFileFeed(ctx, ctx.Repo.Repository, showFeedType) + feed.RenderBranchFeed(ctx, showFeedType) } return true } diff --git a/tests/integration/feed_repo_test.go b/tests/integration/feed_repo_test.go index dcce2cfdb11..53fac34d75a 100644 --- a/tests/integration/feed_repo_test.go +++ b/tests/integration/feed_repo_test.go @@ -51,6 +51,16 @@ func TestFeedRepo(t *testing.T) { assert.NotContains(t, data, "pre-release") assert.NotContains(t, data, "some text for a pre release") }) + + t.Run("BranchFeedWithoutCodeAccess", func(t *testing.T) { + defer tests.PrepareTestEnv(t)() + + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) + require.NoError(t, repo_service.UpdateRepositoryUnits(t.Context(), repo, nil, []unit_model.Type{unit_model.TypeCode})) + MakeRequest(t, NewRequest(t, "GET", "/user2/repo1").SetHeader("Accept", "application/rss+xml"), http.StatusNotFound) + MakeRequest(t, NewRequest(t, "GET", "/user2/repo1").SetHeader("Accept", "application/atom+xml"), http.StatusNotFound) + MakeRequest(t, NewRequest(t, "GET", "/user2/repo1.rss"), http.StatusOK) + }) } // TestFeedRepoContentTokenScopes ensures repository feed endpoints enforce the