Back to blog
AWSBest PracticesCloud SecurityCompute & ContainersOperations & Compliance

ECR Scan on Push Disabled: Why It Matters and How to Fix It

Learn why ECR scan on push matters, how to enable image scanning via CLI, Terraform, and registry defaults, and how to enforce it with CI/CD and policy as code.

TL;DR

This check flags ECR repositories that don't scan images for vulnerabilities when they're pushed, meaning known CVEs can slip into your registry unnoticed. Turn on scan-on-push (or Enhanced Scanning) per repository or set a registry-wide default to fix it.

Container images are made of layers, and every layer carries whatever packages, libraries, and OS components were baked into it. A base image you pulled six months ago can pick up dozens of new CVEs over time without a single byte changing. If Amazon ECR isn't scanning images as they arrive, those vulnerabilities sit silently in your registry until someone deploys them straight into production.

The ECR Scan on Push Disabled check (ecr_imagescans) looks at each ECR repository and verifies that image scanning on push is enabled. When it's off, every image you push lands unscanned.


What this check detects

The check inspects the image scanning configuration on your ECR repositories. Each repository has a imageScanningConfiguration property with a single boolean, scanOnPush. When that value is false (the default for repositories created without explicit configuration), the check fails.

You can confirm the current state for any repository with the CLI:

aws ecr describe-repositories \
  --repository-names my-service \
  --query 'repositories[].imageScanningConfiguration'

A failing repository returns:

[
    {
        "scanOnPush": false
    }
]

Note: ECR has two scanning tiers. Basic scanning uses the open source Clair database and runs either on push or on demand. Enhanced scanning is powered by Amazon Inspector and continuously rescans images as new CVEs are disclosed, covering both OS packages and application dependencies like npm, pip, and Go modules. The scanOnPush flag governs basic scanning; enhanced scanning is configured at the registry level.


Why it matters

Scanning on push closes the gap between "image exists" and "someone deployed it." Without it, you have no automatic signal that an image contains a critical vulnerability, and the discovery often happens after an incident rather than before a deploy.

Here is how this plays out in practice:

  • Vulnerable base images go unnoticed. A team rebuilds a service using an outdated node:18 base layer that ships a vulnerable version of OpenSSL. The image is pushed, pulled by ECS or EKS, and run, all without a single warning.
  • Supply chain risk slips through. A compromised or typosquatted dependency makes it into a build. Scan on push won't catch every malicious package, but it will flag known-vulnerable versions immediately.
  • Compliance gaps. Frameworks like PCI DSS, SOC 2, and the CIS AWS Foundations Benchmark expect vulnerability scanning on container artifacts. An unscanned registry is an easy audit finding.
  • Delayed mean time to detect. When scanning is reactive and manual, vulnerabilities can live in production for weeks. Scan on push gives you findings the moment the image lands.

Warning: Scan on push is not a runtime control. It tells you an image is vulnerable, but it does not stop that image from being pulled or deployed unless you wire findings into an admission or deployment gate. Treat the scan result as a signal, then act on it.


How to fix it

Option 1: Enable scan on push for a single repository (CLI)

The fastest fix for an existing repository is to update its scanning configuration:

aws ecr put-image-scanning-configuration \
  --repository-name my-service \
  --image-scanning-configuration scanOnPush=true

Verify the change took effect:

aws ecr describe-repositories \
  --repository-names my-service \
  --query 'repositories[].imageScanningConfiguration.scanOnPush'

This only affects images pushed after the change. To scan an image that's already in the repository, trigger a manual scan:

aws ecr start-image-scan \
  --repository-name my-service \
  --image-id imageTag=latest

Option 2: Set a registry-wide default (recommended)

Rather than fixing repositories one at a time, configure a scanning rule at the registry level so every existing and future repository is covered. This is where Enhanced Scanning shines, since it continuously rescans without you re-pushing images.

# Enable enhanced (Inspector-backed) continuous scanning for all repositories
aws ecr put-registry-scanning-configuration \
  --scan-type ENHANCED \
  --rules '[
    {
      "scanFrequency": "CONTINUOUS_SCAN",
      "repositoryFilters": [
        { "filter": "*", "filterType": "WILDCARD" }
      ]
    }
  ]'

If you want to stay on basic scanning but still apply it everywhere on push:

aws ecr put-registry-scanning-configuration \
  --scan-type BASIC \
  --rules '[
    {
      "scanFrequency": "SCAN_ON_PUSH",
      "repositoryFilters": [
        { "filter": "*", "filterType": "WILDCARD" }
      ]
    }
  ]'

Warning: Enhanced scanning is billed per image scanned by Amazon Inspector. With CONTINUOUS_SCAN across a large registry, costs scale with the number of images and how often new CVEs are published. Estimate against your image count before flipping it on registry-wide, and use repository filters to scope it if needed.

Option 3: Console

  1. Open the Amazon ECR console.
  2. For a single repo: select the repository, choose Edit, and toggle Scan on push on.
  3. For registry-wide: go to Private registry → Scanning configuration, choose Basic or Enhanced, and add a rule with a wildcard filter.

Fix it in Terraform

For a single repository:

resource "aws_ecr_repository" "service" {
  name = "my-service"

  image_scanning_configuration {
    scan_on_push = true
  }
}

For the registry-wide default with enhanced scanning:

resource "aws_ecr_registry_scanning_configuration" "this" {
  scan_type = "ENHANCED"

  rule {
    scan_frequency = "CONTINUOUS_SCAN"
    repository_filter {
      filter      = "*"
      filter_type = "WILDCARD"
    }
  }
}

Tip: Wrap your ECR repository definition in a shared Terraform module that hardcodes scan_on_push = true. Every team that consumes the module inherits the secure default, and you never have to remember to set it again.


How to prevent it from happening again

Fixing the repositories you have today is the easy part. The harder problem is making sure the next repository someone creates is secure by default.

1. Set the registry default once

The single most effective prevention is the registry-wide scanning configuration shown above. With a wildcard rule in place, a brand-new repository is covered the moment it's created. No per-repository toggle required.

2. Enforce it in CI/CD

Make a passing scan a requirement for promotion, not just an FYI. After pushing in your pipeline, poll for the scan result and fail the build on high or critical findings:

# Wait for the scan to complete, then check findings
aws ecr wait image-scan-complete \
  --repository-name my-service \
  --image-id imageTag="$IMAGE_TAG"

CRITICAL=$(aws ecr describe-image-scan-findings \
  --repository-name my-service \
  --image-id imageTag="$IMAGE_TAG" \
  --query 'imageScanFindings.findingSeverityCounts.CRITICAL' \
  --output text)

if [ "$CRITICAL" != "None" ] && [ "$CRITICAL" -gt 0 ]; then
  echo "Blocking deploy: $CRITICAL critical vulnerabilities found"
  exit 1
fi

3. Gate it with policy as code

Block non-compliant repositories before they're ever created. With Terraform, an OPA/Conftest or Checkov policy can reject any aws_ecr_repository that lacks scan on push:

# Checkov ships a built-in check for exactly this
checkov -d . --check CKV_AWS_163

CKV_AWS_163 ("Ensure ECR image scanning on push is enabled") fails the plan when the configuration is missing, so the misconfiguration never reaches AWS.

4. Catch drift continuously

Registry defaults and policy checks cover the create path, but settings can still be changed by hand after the fact. Continuous monitoring with Lensix re-evaluates ecr_imagescans across every region and account, so a repository that gets flipped back to unscanned shows up as a finding instead of a surprise.

Tip: Route Inspector findings to AWS Security Hub and on to a Slack or PagerDuty channel through EventBridge. That turns a passive scan result into an actionable alert the moment a critical CVE is detected in a pushed image.


Best practices

  • Prefer Enhanced Scanning for anything production facing. Continuous rescanning means you learn about a newly disclosed CVE in an image you pushed months ago, without rebuilding or re-pushing.
  • Pin and refresh base images. Scanning tells you an image is vulnerable; updating the base layer is how you fix it. Rebuild on a schedule so patches actually land.
  • Use immutable tags. Set imageTagMutability=IMMUTABLE so a scanned tag can't be silently overwritten with a different, unscanned image.
  • Define severity thresholds your teams agree on. Blocking on every finding leads to alert fatigue and bypasses. Block on critical and high, track medium and low, and review the thresholds regularly.
  • Apply least privilege to scan controls. Restrict ecr:PutImageScanningConfiguration and ecr:PutRegistryScanningConfiguration so scanning can't be disabled by a stray IAM principal.
  • Scan early in the pipeline too. Tools like Trivy or Grype in CI catch issues before the image even reaches ECR, shortening the feedback loop for developers.

Note: Enabling scan on push and acting on the results are two different milestones. Many teams turn scanning on, generate thousands of findings, and never wire them into a workflow. The value comes from the loop: scan, alert, triage, patch, redeploy.

Enabling image scanning on ECR is a low-effort, high-signal control. Set a registry-wide default, enforce it in CI and policy as code, and monitor for drift so the gap never reopens.