aws-ecr-push-can-modify-code

An IAM principal with effective ecr:PutImage (+ layer-upload actions) on a repository can push/overwrite a mutable-tag image, injecting attacker code into every consumer that re-pulls that tag.

derived aws emits CanModifyCode

match

A conjunctive graph pattern. Variables (?x) bind node ids; every clause must hold.

{'principal': None} HasPermission {'repository': None}

where

node_type(?repository) == ContainerRegistry ?repository.provider_type in ['AWS::ECR::Repository', 'AWS::ECR::PublicRepository'] effective_permission(?principal, 'ecr:PutImage', ?repository) == true effective_permission(?principal, 'ecr:GetAuthorizationToken', '*') == true effective_permission(?principal, 'ecr:InitiateLayerUpload', ?repository) == true effective_permission(?principal, 'ecr:CompleteLayerUpload', ?repository) == true

emit

source typeIdentity
target typeContainerRegistry
source?principal
target?repository
permissionsecr:GetAuthorizationToken ecr:BatchCheckLayerAvailability ecr:InitiateLayerUpload ecr:UploadLayerPart ecr:CompleteLayerUpload ecr:PutImage
conditionsiam_permission resource_policy
state logicACTIVE when ?repository.imageTagMutability == MUTABLE and the principal has all push actions (GetAuthorizationToken registry-wide, PutImage + layer-upload actions on the repository ARN) as effective permissions (identity policy OR repository resource policy grant, not denied by SCP or permission boundary). BLOCKED when ?repository.imageTagMutability == IMMUTABLE — existing tags cannot be overwritten; downgrade to CONDITIONAL(image_tag_mutability) if the attacker also holds ecr:PutImageTagMutability (see aws-ecr-mutability-unblock). CONDITIONAL(resource_policy) when push is granted only via the repository resource policy and the principal's identity policy does not independently authorize it (valid but requires the policy to remain in place). BLOCKED when an SCP or permission boundary denies ecr:PutImage or ecr:GetAuthorizationToken on the relevant scope.

Narrative

{principal.name} can push an image to {repository.name} (ecr:PutImage + ecr:GetAuthorizationToken + layer-upload actions). Overwriting a mutable tag injects attacker-controlled layers into every workload that re-pulls that tag (container-chains image-push-poisons-consumers propagates this to each consumer).

Raw rule rules/derived/aws/ecr.yaml

id: aws-ecr-push-can-modify-code
emits: CanModifyCode
description: An IAM principal with effective ecr:PutImage (+ layer-upload actions) on a repository can
  push/overwrite a mutable-tag image, injecting attacker code into every consumer that re-pulls that tag.
match:
- - principal: null
  - HasPermission
  - repository: null
where:
- node_type(?repository) == ContainerRegistry
- ?repository.provider_type in ['AWS::ECR::Repository', 'AWS::ECR::PublicRepository']
- effective_permission(?principal, 'ecr:PutImage', ?repository) == true
- effective_permission(?principal, 'ecr:GetAuthorizationToken', '*') == true
- effective_permission(?principal, 'ecr:InitiateLayerUpload', ?repository) == true
- effective_permission(?principal, 'ecr:CompleteLayerUpload', ?repository) == true
emit:
  source_type: Identity
  target_type: ContainerRegistry
  source: ?principal
  target: ?repository
  permissions:
  - ecr:GetAuthorizationToken
  - ecr:BatchCheckLayerAvailability
  - ecr:InitiateLayerUpload
  - ecr:UploadLayerPart
  - ecr:CompleteLayerUpload
  - ecr:PutImage
  conditions:
  - iam_permission
  - resource_policy
  state_logic: "ACTIVE when ?repository.imageTagMutability == MUTABLE and the principal has all push actions\
    \ (GetAuthorizationToken registry-wide, PutImage + layer-upload actions on the repository ARN) as\
    \ effective permissions (identity policy OR repository resource policy grant, not denied by SCP or\
    \ permission boundary). BLOCKED when ?repository.imageTagMutability == IMMUTABLE \u2014 existing tags\
    \ cannot be overwritten; downgrade to CONDITIONAL(image_tag_mutability) if the attacker also holds\
    \ ecr:PutImageTagMutability (see aws-ecr-mutability-unblock). CONDITIONAL(resource_policy) when push\
    \ is granted only via the repository resource policy and the principal's identity policy does not\
    \ independently authorize it (valid but requires the policy to remain in place). BLOCKED when an SCP\
    \ or permission boundary denies ecr:PutImage or ecr:GetAuthorizationToken on the relevant scope."
  confidence: 0.95
  derived_from:
  - effective_permission(?principal, ecr:PutImage, ?repository)
  - effective_permission(?principal, ecr:GetAuthorizationToken, *)
  - effective_permission(?principal, ecr:InitiateLayerUpload, ?repository)
  - effective_permission(?principal, ecr:CompleteLayerUpload, ?repository)
  false_positive_note: "PutImage is the controlling action \u2014 the mere presence of layer-upload actions\
    \ without PutImage does NOT constitute CanModifyCode (the manifest is never written). GetAuthorizationToken\
    \ alone does NOT constitute CanModifyCode. For imageTagMutability == IMMUTABLE repositories, emit\
    \ state: BLOCKED for existing tags; new (never-pushed) tags can still be created, but ONLY reach consumers\
    \ whose image reference resolves to that new tag \u2014 effectively no consumer is affected unless\
    \ the consumer's spec changes. Always scope to the exact repository ARN; a wildcard grant on one repo\
    \ does not imply push to another. Honor SCP / permission boundary denials: a deny on ecr:PutImage\
    \ at the OU/account level blocks the push path entirely."
  narrative: '{principal.name} can push an image to {repository.name} (ecr:PutImage + ecr:GetAuthorizationToken
    + layer-upload actions). Overwriting a mutable tag injects attacker-controlled layers into every workload
    that re-pulls that tag (container-chains image-push-poisons-consumers propagates this to each consumer).'
move · open · esc close