Skip to main content
cd ../config-traps
risk/register/ecr-cross-account-pull-policies-without-source-conditions.html
AWS ECR Securityhigh severityAWS ECR

ECR Cross-Account Pull Policies Without Source Conditions

Severity
high
Reviewed
14 Jul 2026
Remediation
~20 minutes
Overview

An ECR repository policy grants pull access to an entire trusted AWS account rather than one specific role, so any principal that account later trusts inherits the same rights, and standard IAM boundaries on the registry side never see the grant to intervene.

Operational summary

At a glance

Symptom
Any IAM principal within the trusted account, including later-added cross-account or third-party roles, calls BatchGetImage against the shared repository.
Likely cause
ECR repository policy grants pull permissions to an entire trusted account root ARN without aws:SourceArn or aws:PrincipalOrgID conditions.
Impact
Every role the trusted account later assumes inherits pull access to the full repository, exposing baked-in secrets in image layers to unintended principals.
Verification signal
Re-run the detection test and a controlled negative-path test.
Safe correction
Scope the repository policy Principal to a specific role ARN and enforce aws:SourceArn and aws:PrincipalOrgID conditions on the grant.
Rollback or recovery
Restore the exported configuration if the new control blocks required production traffic, then narrow the policy before redeployment.

The Trap

A cross-account ECR repository policy that grants ecr:GetDownloadUrlForLayer, ecr:BatchGetImage, and ecr:BatchCheckLayerAvailability to an external AWS account root ARN with no aws:SourceArn or aws:PrincipalOrgID condition attached.

The Default State

AWS’s own cross-account sharing examples, and most aws_ecr_repository_policy Terraform modules copied from them, set the Principal to {"AWS": "arn:aws:iam::<account-id>:root"} and stop there. The console’s Permissions tab reinforces this by defaulting to account-level scoping rather than role-level, so teams sharing a base image with a partner account or a separate CI account tick the box for “grant access” and never add a condition block restricting which role inside that account is doing the pulling.

The Blast Radius

Every IAM principal inside the trusted account inherits pull rights to the entire repository, not just the pipeline role you intended to authorise. That includes roles the account later assumes for third-party SaaS integrations, cross-account CI runners, or any Lambda execution role a developer spins up for testing. Because repository policies sit outside CloudTrail’s default event selectors unless you enable ECR data events explicitly, GuardDuty rarely flags anomalous cross-account pull volume until well after exfiltration. Base images frequently carry embedded secrets baked in during build stages — Dockerfile ARG values, cached .npmrc tokens, leftover AWS credentials from a multi-stage build — and ecr:BatchGetImage returns the full manifest, meaning any principal in the trusted account can retag and re-push those layers into its own registry, propagating the secret downstream with no further authorisation check.

The Lead Mechanic Fix

Scope the resource policy to specific calling identities and enforce organisational and source conditions:

aws ecr set-repository-policy --repository-name prod-api --policy-text file://policy.json

Where policy.json restricts the Principal to a named role ARN and adds:

"Condition": {"StringEquals": {"aws:PrincipalOrgID": "o-xxxxxxxx"}, "ArnLike": {"aws:SourceArn": "arn:aws:sts::<account>:assumed-role/ci-pull-role/*"}}

Enable CloudTrail data events for ecr.amazonaws.com and alert on any BatchGetImage call where the calling userIdentity.arn falls outside the known set of pipeline role ARNs.

03

Apply the safer control

Before you change production

Confirm the affected scope, export the current configuration, and test the replacement control in a non-production environment first.

Fix commands and configuration

aws ecr set-repository-policy --repository-name prod-api --policy-text file://policy.json
policy.json
"Condition": {"StringEquals": {"aws:PrincipalOrgID": "o-xxxxxxxx"}, "ArnLike": {"aws:SourceArn": "arn:aws:sts::<account>:assumed-role/ci-pull-role/*"}}
04

Verify, roll back or escalate

Verify

Re-run the detection test and a controlled negative-path test. Confirm the unsafe behaviour is blocked while approved traffic still succeeds.

Rollback

Restore the exported configuration if the new control blocks required production traffic, then narrow the policy before redeployment.

Escalate

Escalate when the blast radius is uncertain, the control cannot be tested safely, or remediation requires an outage or security exception.

After remediation

Further reading stays below the corrective workflow and is selected by platform, category and shared technical keywords.

Discover more

Connected KBY resources