Container images pulled from an unscanned Azure Container Registry (ACR) are one of the easiest ways for a known CVE to slip into production. A single base image with an outdated OpenSSL package can sit in your registry for months, get pulled into a dozen deployments, and never trigger a single alert — because nothing was watching. Azure Container Registry vulnerability scanning closes that gap by inspecting every image you push for known vulnerabilities before it ever reaches a cluster. In this guide, you'll enable scanning on an existing ACR, wire it up through Microsoft Defender for Containers, trigger an ACR image scan on push, review results in the Azure portal and CLI, and set up alerting so nothing gets deployed silently. By the end, you'll have a repeatable, automated pipeline that catches vulnerable images at the registry layer instead of after they're already running.
Step 1: Confirm Prerequisites and Registry Tier
Before you can turn on scanning, make sure your environment meets the basics:
- An existing Azure Container Registry (Basic, Standard, or Premium tier all support scanning through Defender for Containers).
- Azure CLI version 2.40 or later.
- Contributor or Owner role on the subscription containing the registry, since enabling Defender plans is a subscription-level action.
- The Microsoft Defender for Cloud resource provider registered on your subscription.
Check your CLI version and registry details first:
az --version
az acr show --name myregistry --resource-group myResourceGroup --query "{name:name, sku:sku.name, loginServer:loginServer}"
If the resource provider isn't registered yet, register it now — this is a common source of silent failures later:
az provider register --namespace Microsoft.Security
az provider show --namespace Microsoft.Security --query registrationState
Wait until the state shows Registered before moving on.
Step 2: Enable Microsoft Defender for Containers on the Subscription
ACR vulnerability scanning isn't a standalone toggle — it's delivered through the Microsoft Defender for Containers plan, which covers ACR, AKS, and self-hosted Kubernetes in one plan. Enable it at the subscription level:
az security pricing create \
--name "Containers" \
--tier "Standard"
You can confirm the plan status with:
az security pricing show --name "Containers" --query "{name:name, tier:pricingTier}"
In the Azure portal, this same setting lives under Microsoft Defender for Cloud > Environment Settings > [your subscription] > Defender plans, where "Containers" should read On. This single plan enables Microsoft Defender for Containers ACR coverage across every registry in the subscription — you don't need to configure each registry individually, which is a common point of confusion for teams migrating from the older, per-registry Defender for Container Registries plan that Microsoft retired in 2023.
Step 3: Understand How ACR Image Scan on Push Works
Once the Containers plan is active, Defender automatically performs an ACR image scan on push for any image pushed to a registry in the covered subscription. The scan pulls the image, extracts the OS and language-specific package inventory, and checks it against the Microsoft vulnerability database (informed by Qualys) as well as language-level advisories for npm, pip, Go modules, and similar ecosystems.
A few operational details matter here:
- Scans typically complete within a few minutes of a push, though large multi-layer images can take longer.
- Existing images already in the registry get scanned too — Defender performs a periodic re-scan of images pulled in the last 30 days, since new CVEs are disclosed daily against packages that haven't changed.
- Only images pulled or referenced recently are actively rescanned; fully dormant images won't be rescanned indefinitely, so combine this with a periodic pull or CI job for cold storage.
To manually trigger a fresh evaluation after a policy change, push a no-op tag or re-push the manifest:
az acr import \
--name myregistry \
--source myregistry.azurecr.io/app:latest \
--image app:latest \
--force
Step 4: Perform Azure Container Registry Vulnerability Scanning via CLI and Portal
With scanning active, you have two practical ways to pull results.
Portal path: Navigate to Microsoft Defender for Cloud > Recommendations, then search for "Container registry images should have vulnerability findings resolved." This surfaces every affected image, repository, and tag, along with severity breakdowns and remediation guidance per CVE.
CLI path, useful for scripting and CI gates:
az security assessment list \
--query "[?contains(resourceDetails.Id, 'myregistry')]" \
-o table
For a specific image digest, you can query the sub-assessments (the individual CVE findings) directly:
az rest --method get \
--url "https://management.azure.com/subscriptions/{subId}/resourceGroups/{rg}/providers/Microsoft.ContainerRegistry/registries/myregistry/providers/Microsoft.Security/assessments/{assessmentId}/subAssessments?api-version=2019-01-01-preview"
This is the assessment ID pattern most teams script against when building a pre-deployment gate that blocks a Kubernetes rollout if critical or high findings exist against the image digest being deployed.
Step 5: Configure Alerting and Continuous Export
Scan results are only useful if someone sees them before a bad image ships. Set up continuous export so findings flow into your existing alerting stack instead of living only in the portal:
az security automation create \
--resource-group myResourceGroup \
--automation-name "acr-vuln-export" \
--location eastus \
--sources '[{"eventSource":"Assessments","ruleSets":[]}]' \
--actions '[{"actionType":"LogicApp","logicAppResourceId":"/subscriptions/{subId}/resourceGroups/myResourceGroup/providers/Microsoft.Logic/workflows/notify-team","uri":"https://prod-00.eastus.logic.azure.com/..."}]'
If you'd rather stay entirely in Azure-native tooling, Log Analytics workspace queries against the SecurityRecommendation table let you build a scheduled query rule that fires an alert whenever a new high-severity finding lands against a registry your production clusters pull from.
Step 6: Gate Deployments on Scan Results
Detection without enforcement just produces a dashboard nobody checks. Add a policy that blocks deployment of images with unresolved critical vulnerabilities using Azure Policy:
az policy assignment create \
--name "block-vulnerable-images" \
--policy "Container registry images should have vulnerability findings resolved" \
--scope "/subscriptions/{subId}/resourceGroups/myResourceGroup" \
--params '{"effect":{"value":"Deny"}}'
Pair this with an admission controller check in AKS (Azure Policy for AKS or Gatekeeper) so a vulnerable digest can't be scheduled even if someone bypasses the CI pipeline entirely.
Troubleshooting and Verification
No scan results appear after enabling the plan. Confirm the Defender for Containers plan shows Standard tier, not Free, and that the resource provider Microsoft.Security is registered. New registries can take up to 24 hours to appear in the vulnerability assessment recommendation on first enablement.
Images pushed before enabling the plan show no findings. Defender only scans images pushed or pulled within its active window. Force a re-scan with az acr import --force as shown in Step 3, or trigger a pull from a build agent.
Findings exist but severity looks inconsistent with other scanners. Defender's ACR Defender scanning engine uses the Microsoft/Qualys vulnerability feed, which can differ in CVSS scoring and disclosure timing from Trivy, Grype, or vendor-specific feeds. Cross-reference the CVE ID directly in the NVD if you need a second source of truth rather than comparing raw severity labels across tools.
Policy assignment doesn't block deployments as expected. Policy effects can take up to 30 minutes to propagate, and Deny effects on this built-in policy only apply to new registry pushes, not retroactively to already-deployed workloads — pair it with runtime admission control for full coverage.
Verify end-to-end: push a test image with a known-vulnerable base layer (an old node:14 or python:3.6 tag works reliably), wait 10–15 minutes, and confirm the finding appears in both the portal recommendation and your az security assessment list output. If it shows in one but not the other, the gap is almost always propagation delay rather than a broken pipeline.
How Safeguard Helps
Azure Container Registry vulnerability scanning through Microsoft Defender for Containers is a strong native control, but it's one signal among many in a software supply chain — and it stops at the registry boundary. It won't tell you whether the image was built from a tampered pipeline, whether its SBOM matches what was actually shipped, or whether the same vulnerable base layer is quietly reused across registries in AWS, GCP, or on-prem that Defender never touches.
Safeguard extends that visibility across the full supply chain. We ingest scan findings from ACR, ECR, GCR, and self-hosted registries into a single normalized view, so a critical CVE in a shared base image is visible everywhere it's deployed — not just in the registry where it was first flagged. Safeguard also correlates vulnerability data with build provenance and SBOM attestations, so you can answer questions Defender alone can't: which production services actually run the vulnerable package version, which pipeline produced the image, and whether a fix has already shipped somewhere else in your fleet. For teams already relying on ACR Defender scanning as a first line of defense, Safeguard adds the cross-registry correlation and policy enforcement layer that turns scan results into an auditable, organization-wide remediation workflow instead of a per-registry dashboard.