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.
match
A conjunctive graph pattern. Variables (?x) bind node ids; every clause must hold.
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. |
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.'