This check flags ECR repositories that allow image tags to be overwritten. Mutable tags let an attacker or a careless pipeline silently replace v1.2.0 with different code under the same name. Set the repository to IMMUTABLE so every tag points to exactly one image forever.
You push myapp:v1.2.0, run it through your test suite, and ship it to production. Three weeks later someone pushes a different image to the same v1.2.0 tag. Now the tag you audited, scanned, and signed off on points to code you have never seen. Nothing in your deployment manifests changed, but the bits running in production did.
That is the gap this check closes. When an ECR repository has tag mutability enabled, tags are mutable pointers rather than fixed references, and that breaks one of the core assumptions teams make about container images.
What this check detects
The ecr_mutabletags check inspects every Amazon Elastic Container Registry repository in your account and reports any repository whose imageTagMutability setting is MUTABLE. That is the AWS default, so unless you changed it at creation time, your repositories almost certainly fail this check.
ECR has two mutability modes:
- MUTABLE — an existing tag can be reassigned to a new image digest. Pushing
app:latesttwice overwrites the first push. - IMMUTABLE — once a tag is assigned to an image, ECR rejects any attempt to push that same tag again. You must use a new tag.
Note: A container image is identified two ways: by tag (v1.2.0) and by digest (sha256:abc123...). The digest is content-addressed and never lies about what is inside. The tag is just a human-friendly label that can move. Immutability ties the label down so it always resolves to the same digest.
Why it matters
Mutable tags undermine the trust chain between what you tested and what you run. Here are the concrete ways that bites.
Silent supply chain tampering
If an attacker gains push access to a repository, mutable tags let them overwrite a trusted tag with a malicious image. Your CI pipeline pulls app:prod, your scanners passed it last week, and your Kubernetes deployment references the same tag. None of those checks rerun on every pull, so the swap goes unnoticed until the compromised image is already serving traffic.
Non-reproducible deployments
When a tag can point to different content over time, "redeploy v3.4.1" stops being a deterministic action. A rollback to a known-good version might pull an image that has since been overwritten, which means your rollback does not actually restore the state you expected. Incident response gets much harder when you cannot trust that a tag means what it meant yesterday.
Broken audit and compliance trails
Frameworks like SOC 2, PCI DSS, and supply chain standards such as SLSA expect a verifiable link between a build artifact and what runs in production. Mutable tags break that link. You can attest that v1.2.0 passed your controls, but you cannot prove the running v1.2.0 is the same artifact.
Accidental overwrites from pipelines
Not every risk is malicious. A misconfigured pipeline that reuses a version number, or a developer who tags a hotfix with an existing version, can quietly clobber a production image. With immutable tags, that push fails loudly instead of corrupting your registry.
Warning: The latest tag is the worst offender. It is mutable by design and constantly reassigned. If anything in production references latest, you have no idea what is actually running. Immutability forces you to abandon this anti-pattern.
How to fix it
You change the mutability setting on the repository. The catch: ECR does not let you flip an existing repository's mutability through every interface in every region historically, so the approach depends on whether you are creating new repositories or hardening existing ones.
Check the current setting
aws ecr describe-repositories \
--query 'repositories[].{Name:repositoryName,Mutability:imageTagMutability}' \
--output table
Set mutability on an existing repository
AWS now supports updating mutability in place via put-image-tag-mutability:
aws ecr put-image-tag-mutability \
--repository-name myapp \
--image-tag-mutability IMMUTABLE
Warning: Switching to IMMUTABLE does not break existing images, but it does change pipeline behavior. Any job that overwrites a tag (for example pushing to latest on every build) will start failing. Audit your build scripts before you flip the switch, or you will break deploys.
Create a new repository as immutable
aws ecr create-repository \
--repository-name myapp \
--image-tag-mutability IMMUTABLE \
--image-scanning-configuration scanOnPush=true
Console steps
- Open the Amazon ECR console and select Repositories.
- Click the repository name, then Edit in the top right.
- Under Tag immutability, toggle the setting to Enabled.
- Save. New pushes to existing tags will now be rejected.
Fix it in Terraform
resource "aws_ecr_repository" "myapp" {
name = "myapp"
image_tag_mutability = "IMMUTABLE"
image_scanning_configuration {
scan_on_push = true
}
}
Fix it in CloudFormation
Resources:
MyAppRepo:
Type: AWS::ECR::Repository
Properties:
RepositoryName: myapp
ImageTagMutability: IMMUTABLE
ImageScanningConfiguration:
ScanOnPush: true
Tip: Update your pipeline to tag images with the immutable Git commit SHA, for example myapp:git-9f2a1b7, instead of mutable labels. The SHA is unique per build, so it never collides with an existing tag, and it traces every running image straight back to a commit.
How to prevent it from happening again
Fixing the repositories you have today is the easy part. Keeping new ones from drifting back to mutable is where automation earns its keep.
Block mutable repositories with an SCP or IAM policy
You can deny the creation of mutable repositories at the organization level. This condition rejects any CreateRepository or PutImageTagMutability call that sets the value to MUTABLE:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "DenyMutableEcrTags",
"Effect": "Deny",
"Action": [
"ecr:CreateRepository",
"ecr:PutImageTagMutability"
],
"Resource": "*",
"Condition": {
"StringEquals": {
"ecr:image-tag-mutability": "MUTABLE"
}
}
}
]
}
Note: Condition key support for ECR mutability can vary. Test this in a non-production account first and confirm the deny fires as expected before rolling it out org-wide.
Catch it in CI with policy-as-code
Scan your Terraform before it ever reaches AWS. With Checkov:
checkov -d . --check CKV_AWS_51
CKV_AWS_51 fails any aws_ecr_repository that does not set image_tag_mutability = "IMMUTABLE". Wire it into a pull request gate so misconfigured repositories cannot be merged.
For OPA / Conftest users, a Rego rule does the same job against a Terraform plan:
package main
deny[msg] {
resource := input.resource_changes[_]
resource.type == "aws_ecr_repository"
resource.change.after.image_tag_mutability != "IMMUTABLE"
msg := sprintf("ECR repo '%s' must be IMMUTABLE", [resource.name])
}
Run Lensix continuously
Policy gates catch new infrastructure, but they miss repositories created by hand, by a one-off script, or before the gate existed. The ecr_mutabletags check runs against your live account, so it surfaces drift no matter how the repository was created. Pair the preventive gate with the continuous check and you cover both the front door and the windows.
Best practices
- Make immutability the default everywhere. Bake
IMMUTABLEinto your repository module so nobody has to remember it. - Tag with commit SHAs or semantic versions, never reuse. Treat a tag as a write-once reference. If you need a moving pointer for a tracking, resolve it to a digest at deploy time.
- Pin deployments to digests. In Kubernetes and ECS, reference images by digest (
myapp@sha256:...) rather than tag for the strongest guarantee about what runs. - Enable scan-on-push alongside immutability. Immutability tells you the image did not change; scanning tells you whether it was safe to begin with.
- Sign your images. Combine immutable tags with image signing (for example Cosign and AWS Signer) so consumers can verify both identity and integrity.
- Set lifecycle policies. Immutable tags mean you cannot overwrite old images, so untagged and stale images accumulate. A lifecycle policy keeps storage costs in check.
Tip: Add a lifecycle rule that expires untagged images after a few days. It cleans up the orphaned layers that immutability tends to leave behind without touching anything you reference by tag.
Immutable tags are not a security feature you bolt on, they are a property you build everything else on. Scanning, signing, and audit trails all assume a tag means one thing. Immutability is what makes that assumption true.
Flip your repositories to IMMUTABLE, gate new ones in CI, and let Lensix watch for drift. It is a small change with an outsized payoff for the trustworthiness of everything you ship.

