Repository navigation
fix(actions): deny fork-PR cross-repo access via collaborative owner - #38214
Merged
bircni merged 3 commits intoJun 28, 2026
Merged
Conversation
The collaborative-owner branch in GetActionsUserRepoPermission granted code-read to a target private repository whenever its Actions config trusted the task repo's owner, but unlike every sibling path it did not check task.IsForkPullRequest. An attacker-controlled fork-PR workflow could therefore clone a third private repository it has no rights to. Add the same fork-PR guard the sibling checkSameOwnerCrossRepoAccess enforces, and add a regression test covering both the legitimate non-fork grant and the fork-PR denial. Assisted-by: Claude:claude-opus-4-8
lunny
approved these changes
Jun 25, 2026
TheFox0x7
approved these changes
Jun 28, 2026
bircni
enabled auto-merge (squash)
June 28, 2026 10:08
zeekay
pushed a commit
to hanzoai/forge
that referenced
this pull request
Jul 26, 2026
…o-gitea#38214) ### What `GetActionsUserRepoPermission` (`models/perm/access/repo_permission.go`) decides whether an Actions task token may access a target repo. Its cross-repo branches each enforce a fork-PR discriminator — except the collaborative-owner branch, which was missing the `!task.IsForkPullRequest` guard that its sibling `checkSameOwnerCrossRepoAccess` has. As a result, when a private repo **B** lists owner **A** as a collaborative owner, an attacker-controlled fork pull-request workflow whose base repo is owned by A was granted code-read on B — i.e. the fork's workflow could clone a third private repository it has no rights to (read-only confidentiality breach). ### Fix Add the same fork-PR guard the sibling path already enforces: ```go if taskRepo.IsPrivate && !task.IsForkPullRequest { actionsUnit := repo.MustGetUnit(ctx, unit.TypeActions) if actionsUnit.ActionsConfig().IsCollaborativeOwner(taskRepo.OwnerID) { return maxPerm, nil } } ```
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to subscribe to this conversation on GitHub.
Already have an account?
Sign in.
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
GetActionsUserRepoPermission(models/perm/access/repo_permission.go) decides whether an Actions task token may access a target repo. Its cross-repo branches each enforce a fork-PR discriminator — except the collaborative-owner branch, which was missing the!task.IsForkPullRequestguard that its siblingcheckSameOwnerCrossRepoAccesshas.As a result, when a private repo B lists owner A as a collaborative owner, an attacker-controlled fork pull-request workflow whose base repo is owned by A was granted code-read on B — i.e. the fork's workflow could clone a third private repository it has no rights to (read-only confidentiality breach).
Fix
Add the same fork-PR guard the sibling path already enforces: