gcp-sr-cross-project-writer
A CSR repo IAM binding that grants source.repos.update to a service account from a different GCP project establishes cross-project trust - that SA can push to this project's repository and arm Cloud Build triggers.
match
A conjunctive graph pattern. Variables (?x) bind node ids; every clause must hold.
where
?repo is a CSR
ArtifactRepository
?repo_policy is a ResourcePolicy of the CSR repository
?repo_policy has an IAM binding for a ServiceAccount from a DIFFERENT GCP project (member is serviceAccount:*@<other-project>.iam.gserviceaccount.com)
the binding role or permissions include source.repos.update
emit
| source type | ResourcePolicy |
|---|---|
| target type | Project |
| source | ?repo_policy |
| target | <GCP project of the external ServiceAccount> |
| permissions | source.repos.update |
| conditions | resource_policy |
| state logic | ACTIVE when the IAM binding is present, the role includes source.repos.update, and no IAM deny policy overrides it. CONDITIONAL (resource_policy) if the binding has an IAM condition expression that may not be satisfied. BLOCKED if a VPC-SC perimeter rejects the cross- project API call or an org policy restricts cross-project resource sharing. Inherit weakest from the binding's effective state. |
Narrative
Repository {repo.name} (project {repo.project}) grants source.repos.update to service account {sa.name} from project {sa.project}. A principal that can act as {sa.name} can push commits to {repo.name}, arming any Cloud Build push trigger watching a target branch in {repo.project}.
Raw rule rules/derived/gcp/sourcerepos.yaml
id: gcp-sr-cross-project-writer
emits: CrossProjectTrust
description: "A CSR repo IAM binding that grants source.repos.update to a service account from a different\
\ GCP project establishes cross-project trust \u2014 that SA can push to this project's repository and\
\ arm Cloud Build triggers."
match:
- - repo: null
- HasPolicy
- repo_policy: null
where:
- ?repo is a CSR ArtifactRepository
- ?repo_policy is a ResourcePolicy of the CSR repository
- ?repo_policy has an IAM binding for a ServiceAccount from a DIFFERENT GCP project (member is serviceAccount:*@<other-project>.iam.gserviceaccount.com)
- the binding role or permissions include source.repos.update
emit:
source_type: ResourcePolicy
target_type: Project
source: ?repo_policy
target: <GCP project of the external ServiceAccount>
permissions:
- source.repos.update
conditions:
- resource_policy
state_logic: ACTIVE when the IAM binding is present, the role includes source.repos.update, and no IAM
deny policy overrides it. CONDITIONAL (resource_policy) if the binding has an IAM condition expression
that may not be satisfied. BLOCKED if a VPC-SC perimeter rejects the cross- project API call or an
org policy restricts cross-project resource sharing. Inherit weakest from the binding's effective
state.
confidence: 0.9
derived_from:
- 'IAM binding on ?repo_policy: <external SA> has source.repos.update'
false_positive_note: "The cross-project SA must be usable by a principal the attacker controls \u2014\
\ this trust edge models the repo's posture, not that the SA is compromised. Path-finding chains this\
\ CrossProjectTrust to the SA's home project; only if a principal there can act as the SA (actAs or\
\ direct key) does the push materialize. Verify the SA is not a Google-managed service agent (those\
\ have restricted actAs surfaces)."
narrative: Repository {repo.name} (project {repo.project}) grants source.repos.update to service account
{sa.name} from project {sa.project}. A principal that can act as {sa.name} can push commits to {repo.name},
arming any Cloud Build push trigger watching a target branch in {repo.project}.