Skip to content

fix(actions): deny fork-PR cross-repo access via collaborative owner - #38214

Merged
bircni merged 3 commits into
go-gitea:mainfrom
bircni:fix-fork-pr-collaborative-owner-access
Jun 28, 2026
Merged

bircni merged 3 commits into
go-gitea:mainfrom
bircni:fix-fork-pr-collaborative-owner-access

Conversation

@bircni

@bircni bircni commented Jun 25, 2026 •

Copy link
Copy Markdown
Member

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:

if taskRepo.IsPrivate && !task.IsForkPullRequest {
    actionsUnit := repo.MustGetUnit(ctx, unit.TypeActions)
    if actionsUnit.ActionsConfig().IsCollaborativeOwner(taskRepo.OwnerID) {
        return maxPerm, nil
    }
}

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
@GiteaBot GiteaBot added the lgtm/need 2 This PR needs two approvals by maintainers to be considered for merging. label Jun 25, 2026
@bircni bircni added this to the 1.27.0 milestone Jun 25, 2026
@GiteaBot GiteaBot added lgtm/need 1 This PR needs approval from one additional maintainer to be merged. and removed lgtm/need 2 This PR needs two approvals by maintainers to be considered for merging. labels Jun 25, 2026
@GiteaBot GiteaBot added lgtm/done This PR has enough approvals to get merged. There are no important open reservations anymore. and removed lgtm/need 1 This PR needs approval from one additional maintainer to be merged. labels Jun 28, 2026
@bircni
bircni enabled auto-merge (squash) June 28, 2026 10:08
@bircni bircni added the reviewed/wait-merge This pull request is part of the merge queue. It will be merged soon. label Jun 28, 2026
@bircni
bircni merged commit 1d43b73 into go-gitea:main Jun 28, 2026
26 checks passed
@GiteaBot GiteaBot removed the reviewed/wait-merge This pull request is part of the merge queue. It will be merged soon. label Jun 28, 2026
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
    }
}
```
@go-gitea go-gitea locked as resolved and limited conversation to collaborators Sep 26, 2026
@bircni
bircni deleted the fix-fork-pr-collaborative-owner-access branch October 3, 2026 23:16
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

lgtm/done This PR has enough approvals to get merged. There are no important open reservations anymore. type/bug

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants