Back to blog
AzureBest PracticesCloud SecurityCompute & ContainersOperations & Compliance

VM Auto-Update Disabled: Patching Azure Windows VMs the Right Way

Learn why disabled automatic updates on Azure Windows VMs is a security risk, how to enable patching via CLI, Terraform, and Azure Update Manager, and how to enforce it.

TL;DR

This check flags Azure Windows VMs running without automatic updates, which leaves them exposed to known, patchable vulnerabilities. Enable enableAutomaticUpdates on the VM's OS profile or move patching to Azure Update Manager so security fixes land without manual effort.

Unpatched Windows servers are one of the most reliable ways for an attacker to get a foothold. Most breaches that exploit known CVEs do so months after a fix was published, not on day zero. The gap between "patch exists" and "patch applied" is where the damage happens, and a VM with automatic updates turned off can sit in that gap indefinitely.

The Lensix VM Auto-Update Disabled check (vm_autoupdate) looks at your Azure Windows VMs and reports any where automatic updates are not enabled. It is a small setting with an outsized impact on your patch posture.


What this check detects

When you provision a Windows VM in Azure, the OS profile includes a Windows configuration block with a property called enableAutomaticUpdates. When this is set to true, the guest OS uses Windows Update to download and install updates automatically. When it is false, the VM only gets updates if a human or an external tool installs them.

The check inspects each Windows VM's osProfile.windowsConfiguration.enableAutomaticUpdates value and flags any VM where it is disabled or unset in a way that disables it.

Note: This setting controls the in-guest Windows Update behavior at provision time. It is distinct from Azure Update Manager and from Automatic VM Guest Patching, which are platform-level patching services. Many mature environments turn the in-guest setting off on purpose because they centralize patching elsewhere. More on that below.


Why it matters

A VM that never patches itself accumulates risk linearly with time. Every Patch Tuesday adds more unaddressed CVEs to the pile. The practical consequences fall into a few buckets:

  • Exploitable remote vulnerabilities. Bugs like the SMB and RDP flaws behind EternalBlue and BlueKeep were wormable and remotely exploitable. Servers that missed those patches got compromised at scale, often within weeks of public disclosure.
  • Privilege escalation. Local elevation-of-privilege bugs let an attacker who already has a low-privilege session become SYSTEM. Without patches, these stay open for anyone who gets initial access.
  • Compliance gaps. Frameworks like PCI DSS, SOC 2, ISO 27001, and CIS benchmarks all expect a defined, enforced patch cadence. An unpatched, no-auto-update VM is a finding waiting to happen during an audit.
  • Ransomware blast radius. Most ransomware operators move laterally using unpatched services. One stale VM can be the pivot point that turns a contained incident into a domain-wide event.

The real-world pattern is consistent: the vulnerability is known, the patch is available, and the only thing missing is that someone forgot to apply it. Automatic updates close that loop.

Warning: "Auto-update disabled" is not automatically a misconfiguration. If you patch through Azure Update Manager, WSUS, SCCM, or an immutable-image pipeline, the in-guest setting may be off by design. Treat this check as a prompt to confirm a patching mechanism exists, not just to flip a flag.


How to fix it

There are two valid directions: enable in-guest automatic updates, or adopt a centralized patching service. Pick based on how you manage your fleet.

Option 1: Enable automatic updates on an existing VM (Azure CLI)

You can update the OS profile of a running VM. This takes effect without recreating the machine.

Warning: Enabling automatic updates means the guest may reboot to finish installing patches. For servers without redundancy, schedule this during a maintenance window or pair it with Update Manager maintenance configurations to control timing.

az vm update \
  --resource-group my-rg \
  --name my-windows-vm \
  --set osProfile.windowsConfiguration.enableAutomaticUpdates=true

Confirm the change took effect:

az vm show \
  --resource-group my-rg \
  --name my-windows-vm \
  --query "osProfile.windowsConfiguration.enableAutomaticUpdates"

The output should be true.

Option 2: Use Azure Update Manager (recommended for fleets)

For anything beyond a handful of VMs, in-guest auto-update is hard to coordinate. Azure Update Manager gives you scheduled patching, maintenance windows, compliance reporting, and assessment across the whole fleet. Enable periodic assessment and a maintenance configuration:

# Turn on periodic assessment so Azure tracks missing patches
az vm update \
  --resource-group my-rg \
  --name my-windows-vm \
  --set "osProfile.windowsConfiguration.patchSettings.assessmentMode=AutomaticByPlatform" \
  --set "osProfile.windowsConfiguration.patchSettings.patchMode=AutomaticByPlatform"

Then create a maintenance configuration and attach VMs so patching runs on a predictable schedule rather than whenever Windows Update decides to act.

Tip: AutomaticByPlatform patch mode lets Azure orchestrate reboots within a maintenance window you define. This is usually a better fit for production than raw in-guest auto-update, because you control when the disruption happens.

Option 3: Fix it in the Azure Portal

  1. Open the Virtual Machine in the Azure Portal.
  2. Go to Settings > Updates (or Operations > Updates depending on the portal version).
  3. Choose Update settings and set the patch orchestration to Azure-orchestrated (Automatic by platform) or enable periodic assessment.
  4. Save, then trigger a one-time assessment to see current patch status.

Fix it in Infrastructure as Code

The durable fix is in your IaC so new VMs are never created without it. Terraform example:

resource "azurerm_windows_virtual_machine" "app" {
  name                = "app-vm-01"
  resource_group_name = azurerm_resource_group.main.name
  location            = azurerm_resource_group.main.location
  size                = "Standard_D2s_v5"
  admin_username      = "azureadmin"
  admin_password      = var.admin_password

  enable_automatic_updates = true
  patch_mode               = "AutomaticByPlatform"
  patch_assessment_mode    = "AutomaticByPlatform"

  network_interface_ids = [azurerm_network_interface.app.id]

  os_disk {
    caching              = "ReadWrite"
    storage_account_type = "Standard_LRS"
  }

  source_image_reference {
    publisher = "MicrosoftWindowsServer"
    offer     = "WindowsServer"
    sku       = "2022-datacenter-azure-edition"
    version   = "latest"
  }
}

And the equivalent in a Bicep template:

"osProfile": {
  "computerName": "app-vm-01",
  "adminUsername": "azureadmin",
  "windowsConfiguration": {
    "enableAutomaticUpdates": true,
    "patchSettings": {
      "patchMode": "AutomaticByPlatform",
      "assessmentMode": "AutomaticByPlatform"
    }
  }
}

How to prevent it from happening again

Flipping the setting once does nothing for the next VM someone spins up. Bake the requirement into the pipeline so it is enforced, not remembered.

Enforce with Azure Policy

Azure has built-in policy definitions to require patch settings and to deploy the Update Manager configuration. Assign the policy initiative Configure periodic checking for missing system updates on Azure virtual machines, or write a custom audit policy that denies VMs with automatic updates disabled. A simplified custom rule:

{
  "if": {
    "allOf": [
      { "field": "type", "equals": "Microsoft.Compute/virtualMachines" },
      { "field": "Microsoft.Compute/virtualMachines/osProfile.windowsConfiguration.enableAutomaticUpdates", "equals": "false" }
    ]
  },
  "then": {
    "effect": "audit"
  }
}

Tip: Start with audit effect to measure how many existing VMs fail, then switch to deny once you have remediated the backlog. Flipping straight to deny on a noisy estate will block legitimate deployments and frustrate teams.

Gate it in CI/CD

Catch the problem before it reaches Azure by scanning Terraform and Bicep in your pipeline. Tools like Checkov, tfsec, or terraform-compliance can fail a build when a Windows VM lacks the right patch settings. A Checkov run in a pull request gate looks like:

checkov -d ./infra --framework terraform \
  --check CKV_AZURE_50 --compact

Wire the Lensix vm_autoupdate check into your scheduled scans too, so drift introduced outside of IaC (manual portal changes, for example) gets surfaced quickly.


Best practices

  • Centralize patching with Azure Update Manager. It scales better than per-VM auto-update and gives you compliance reporting auditors actually want to see.
  • Use maintenance windows. Control when reboots happen rather than letting them surprise you in the middle of a busy period.
  • Prefer immutable images where you can. For stateless workloads, baking patches into a golden image and redeploying is often safer than in-place patching.
  • Monitor patch compliance, not just patch settings. A VM can have auto-update enabled and still be behind if it cannot reach update endpoints. Track actual installed-versus-available patch state.
  • Document exceptions. If a VM legitimately has auto-update off because it is patched by SCCM or an image pipeline, record that so the finding can be suppressed with context instead of silently ignored.
  • Test patches in non-production first. Use ring-based rollout so a bad update does not take down everything at once.

Danger: Never disable automatic updates on an internet-facing Windows VM and leave it without an alternate patching mechanism. A public IP plus an unpatched RDP or SMB service is among the fastest ways to get a host compromised, and it puts everything reachable from that host at risk.

The bottom line: this check is cheap to satisfy and expensive to ignore. Either enable automatic updates or prove you patch by another route, then enforce that choice in policy and CI so it stays true for every VM you create next.