gcp-gcr-read-layers
storage.objects.get on the GCR artifacts bucket = pull container image layers for inspection (embedded credential exfil / code recon) without push capability.
match (effective permission)
{
"action": "storage.objects.get",
"resource_type": "storage.googleapis.com/Bucket"
}
where
resource.name matches 'artifacts.<PROJECT>.appspot.com' (the GCR artifacts backing bucket, not an arbitrary GCS bucket)
The principal has effective storage.objects.get but NOT storage.objects.create on the artifacts bucket (pure pull, not push).
The GCR endpoint is GCS-backed (legacy GCR active).
emit
| source type | Identity |
|---|---|
| target type | ContainerRegistry |
| source | <principal with effective storage.objects.get on the artifacts bucket> |
| target | <ContainerRegistry node for gcr.io/PROJECT> |
| permissions | storage.objects.get |
| state logic | ACTIVE when the principal holds effective storage.objects.get on artifacts.PROJECT.appspot.com. BLOCKED when VPC Service Controls denies storage.googleapis.com access for the principal from outside the perimeter. |
Narrative
{principal.name} can pull container images from the GCR registry for project {project.name} (storage.objects.get on artifacts.{project.name}.appspot.com), enabling inspection of image layers for embedded credentials, configuration, or proprietary code. This is a read-only capability; it does not permit image push or supply-chain poisoning.
Raw rule rules/derived/gcp/gcr.yaml
id: gcp-gcr-read-layers
emits: CanRead
description: storage.objects.get on the GCR artifacts bucket = pull container image layers for inspection
(embedded credential exfil / code recon) without push capability.
match_effective_permission:
action: storage.objects.get
resource_type: storage.googleapis.com/Bucket
where:
- resource.name matches 'artifacts.<PROJECT>.appspot.com' (the GCR artifacts backing bucket, not an arbitrary
GCS bucket)
- The principal has effective storage.objects.get but NOT storage.objects.create on the artifacts bucket
(pure pull, not push).
- The GCR endpoint is GCS-backed (legacy GCR active).
emit:
source_type: Identity
target_type: ContainerRegistry
source: <principal with effective storage.objects.get on the artifacts bucket>
target: <ContainerRegistry node for gcr.io/PROJECT>
permissions:
- storage.objects.get
conditions: []
state_logic: ACTIVE when the principal holds effective storage.objects.get on artifacts.PROJECT.appspot.com.
BLOCKED when VPC Service Controls denies storage.googleapis.com access for the principal from outside
the perimeter.
confidence: 0.85
derived_from:
- effective storage.objects.get on artifacts.<PROJECT>.appspot.com
false_positive_note: "Pull access (storage.objects.get) is not a code injection primitive; it enables\
\ image layer inspection, which is relevant when images contain embedded secrets (leading to a CanReadSecret\
\ / ExposesCredential path if confirmed by layer scanning). Do not conflate storage.objects.get with\
\ storage.objects.create: pull-only principals cannot push/overwrite images. The Compute Engine default\
\ SA and most GCE/GKE workloads have this permission by default \u2014 this rule produces a large\
\ number of CanRead edges in a typical project; filter by is_external=true or high_value=true for\
\ path-finding relevance."
narrative: '{principal.name} can pull container images from the GCR registry for project {project.name}
(storage.objects.get on artifacts.{project.name}.appspot.com), enabling inspection of image layers
for embedded credentials, configuration, or proprietary code. This is a read-only capability; it does
not permit image push or supply-chain poisoning.'