aws-ecr-delete-policy-can-modify-policy

A principal with ecr:DeleteRepositoryPolicy can delete the repository resource policy, removing all access controls and cross-account restrictions - policy-mutation escalation.

derived aws emits CanModifyPolicy

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'] effective_permission(?principal, 'ecr:DeleteRepositoryPolicy', ?repository) == true

emit

source typeIdentity
target typeResourcePolicy
source?principal
target<repository policy of ?repository>
permissionsecr:DeleteRepositoryPolicy
conditionsiam_permission
state logicACTIVE when the principal has effective ecr:DeleteRepositoryPolicy on the repository (not denied by SCP or permission boundary). Deleting the policy removes all resource-based access controls; the principal can then set a new policy granting themselves push access (two-step: delete + SetRepositoryPolicy). BLOCKED when an SCP or permission boundary denies ecr:DeleteRepositoryPolicy.

Narrative

{principal.name} can delete the resource policy of {repository.name} (ecr:DeleteRepositoryPolicy), removing all existing access controls and cross-account restrictions. This enables a two-step escalation: delete the protective policy, then set a new policy granting push access.

Raw rule rules/derived/aws/ecr.yaml

id: aws-ecr-delete-policy-can-modify-policy
emits: CanModifyPolicy
description: "A principal with ecr:DeleteRepositoryPolicy can delete the repository resource policy, removing\
  \ all access controls and cross-account restrictions \u2014 policy-mutation escalation."
match:
- - principal: null
  - HasPermission
  - repository: null
where:
- node_type(?repository) == ContainerRegistry
- ?repository.provider_type in ['AWS::ECR::Repository']
- effective_permission(?principal, 'ecr:DeleteRepositoryPolicy', ?repository) == true
emit:
  source_type: Identity
  target_type: ResourcePolicy
  source: ?principal
  target: <repository policy of ?repository>
  permissions:
  - ecr:DeleteRepositoryPolicy
  conditions:
  - iam_permission
  state_logic: 'ACTIVE when the principal has effective ecr:DeleteRepositoryPolicy on the repository (not
    denied by SCP or permission boundary). Deleting the policy removes all resource-based access controls;
    the principal can then set a new policy granting themselves push access (two-step: delete + SetRepositoryPolicy).
    BLOCKED when an SCP or permission boundary denies ecr:DeleteRepositoryPolicy.'
  confidence: 0.9
  derived_from:
  - effective_permission(?principal, ecr:DeleteRepositoryPolicy, ?repository)
  false_positive_note: "DeleteRepositoryPolicy removes all resource-based controls but does not by itself\
    \ grant push access \u2014 the principal must follow up with SetRepositoryPolicy to add a new grant.\
    \ The escalation chain is: DeleteRepositoryPolicy (remove protections) + SetRepositoryPolicy (self-grant\
    \ push) + PutImage. Emit this edge to capture the policy-mutation capability; the engine will derive\
    \ subsequent escalation steps after the policy delete is modeled and a new policy is set."
  narrative: '{principal.name} can delete the resource policy of {repository.name} (ecr:DeleteRepositoryPolicy),
    removing all existing access controls and cross-account restrictions. This enables a two-step escalation:
    delete the protective policy, then set a new policy granting push access.'
move · open · esc close