mirror of
https://github.com/go-gitea/gitea.git
synced 2026-06-29 14:21:25 +00:00
fix(actions): deny fork-PR cross-repo access via collaborative owner (#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 commit is contained in:
@@ -95,6 +95,40 @@ func TestGetActionsUserRepoPermission(t *testing.T) {
|
||||
assert.False(t, perm.CanRead(unit.TypeCode))
|
||||
})
|
||||
|
||||
t.Run("CollaborativeOwner_ForkPR_Denied", func(t *testing.T) {
|
||||
// Target repo15 trusts repo2's owner as a collaborative owner.
|
||||
repo15ActionsUnit := repo15.MustGetUnit(ctx, unit.TypeActions)
|
||||
repo15ActionsUnit.ActionsConfig().AddCollaborativeOwner(owner2.ID)
|
||||
require.NoError(t, repo_model.UpdateRepoUnitConfig(ctx, repo15ActionsUnit))
|
||||
|
||||
// Owner cross-repo policy does not allow repo15, so the only branch that
|
||||
// could grant access is the collaborative-owner one.
|
||||
require.NoError(t, actions_model.SetOwnerActionsConfig(ctx, owner2.ID, actions_model.OwnerActionsConfig{}))
|
||||
|
||||
task53 := unittest.AssertExistsAndLoadBean(t, &actions_model.ActionTask{ID: 53})
|
||||
|
||||
// Non-fork task is legitimately granted code-read via collaborative owner.
|
||||
task53.IsForkPullRequest = false
|
||||
require.NoError(t, actions_model.UpdateTask(ctx, task53, "is_fork_pull_request"))
|
||||
perm, err := GetActionsUserRepoPermission(ctx, repo15, actionsUser, task53.ID)
|
||||
require.NoError(t, err)
|
||||
assert.True(t, perm.CanRead(unit.TypeCode))
|
||||
|
||||
// Fork PR must NOT be able to read a third private repo through the
|
||||
// collaborative-owner branch.
|
||||
task53.IsForkPullRequest = true
|
||||
require.NoError(t, actions_model.UpdateTask(ctx, task53, "is_fork_pull_request"))
|
||||
perm, err = GetActionsUserRepoPermission(ctx, repo15, actionsUser, task53.ID)
|
||||
require.NoError(t, err)
|
||||
assert.False(t, perm.CanRead(unit.TypeCode))
|
||||
|
||||
// Restore state for subsequent subtests.
|
||||
task53.IsForkPullRequest = false
|
||||
require.NoError(t, actions_model.UpdateTask(ctx, task53, "is_fork_pull_request"))
|
||||
repo15ActionsUnit.ActionsConfig().RemoveCollaborativeOwner(owner2.ID)
|
||||
require.NoError(t, repo_model.UpdateRepoUnitConfig(ctx, repo15ActionsUnit))
|
||||
})
|
||||
|
||||
t.Run("Inheritance_And_Clamping", func(t *testing.T) {
|
||||
task53 := unittest.AssertExistsAndLoadBean(t, &actions_model.ActionTask{ID: 53})
|
||||
task53.IsForkPullRequest = false
|
||||
|
||||
@@ -369,7 +369,9 @@ func GetActionsUserRepoPermission(ctx context.Context, repo *repo_model.Reposito
|
||||
// 2. The Actions Bot user has been explicitly granted access and repository is private
|
||||
// 3. The repository is public (handled by botPerm above)
|
||||
|
||||
if taskRepo.IsPrivate {
|
||||
// Fork PRs are never allowed cross-repo access to other private repositories,
|
||||
// matching the discriminator enforced by checkSameOwnerCrossRepoAccess above.
|
||||
if taskRepo.IsPrivate && !task.IsForkPullRequest {
|
||||
actionsUnit := repo.MustGetUnit(ctx, unit.TypeActions)
|
||||
if actionsUnit.ActionsConfig().IsCollaborativeOwner(taskRepo.OwnerID) {
|
||||
return maxPerm, nil
|
||||
|
||||
Reference in New Issue
Block a user