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.

derived gcp emits CanRead

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 typeIdentity
target typeContainerRegistry
source<principal with effective storage.objects.get on the artifacts bucket>
target<ContainerRegistry node for gcr.io/PROJECT>
permissionsstorage.objects.get
state logicACTIVE 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.'
move · open · esc close