This check flags Azure managed disks that aren't attached to any VM. They keep billing you every month and can hold sensitive data that outlives the workload that created them. Snapshot anything worth keeping, then delete the orphans.
Unattached managed disks are one of the most common forms of cloud waste in Azure, and they tend to pile up quietly. Every time someone deletes a VM without ticking the box to remove its data disks, or detaches a disk during troubleshooting and forgets about it, that disk keeps existing as a standalone resource. It still consumes its full provisioned capacity, still appears on your invoice, and still holds whatever data was on it the moment it was detached.
This Lensix check, vm_unattacheddisks, scans your subscriptions for managed disks whose diskState is not Attached and reports them so you can decide what to keep and what to clean up.
What this check detects
The check looks at every managed disk in scope and inspects its attachment status. A managed disk in Azure can be in one of several states:
- Attached — the disk is connected to a running or stopped VM.
- Unattached — the disk exists but is not connected to any VM.
- Reserved — the disk was attached to a VM that is now deallocated, but the association still exists.
- ActiveSAS — the disk has an active SAS URI, often used for export or upload.
This check raises a finding for disks in the Unattached state. These are disks paying rent with nobody living in them.
Note: Managed disks are billed on provisioned size, not used size. A 1 TiB Premium SSD disk that is empty and unattached still costs the same as a full one. Detaching a disk does not reduce its cost at all.
Why it matters
There are two angles here, and both are worth taking seriously.
Cost
Unattached disks are pure waste. A single orphaned Premium SSD P40 (2 TiB) runs roughly $290 per month in most regions. Multiply that across a few dozen forgotten disks left behind by deleted VMs and old test environments, and you are looking at thousands of dollars a year for storage nobody uses. Because the disks don't appear in the VM blade, they're easy to miss during cost reviews.
Security and data residency
This is the part teams often overlook. A detached disk still contains every byte that was on it when it left the VM, including OS files, application data, credentials in config files, cached tokens, and database files. An attacker who gains read access to your subscription, or a misconfigured RBAC assignment, can create a snapshot of an unattached disk, export it via a SAS URI, and exfiltrate the contents without ever touching a running VM.
Warning: Old disks also create compliance headaches. If a customer requests deletion of their data under GDPR or a similar regulation, an orphaned disk that still holds that data is a finding waiting to happen during an audit. "We deleted the VM" is not the same as "we deleted the data."
So an unattached disk is both a line item you don't need and a piece of attack surface you forgot you had.
How to fix it
The fix is to identify orphaned disks, preserve anything you might still need, and delete the rest. Do not skip the preservation step.
Step 1: Find unattached disks
Use the Azure CLI to list every managed disk with no attachment. This query works across your current subscription:
az disk list \
--query "[?diskState=='Unattached'].{Name:name, RG:resourceGroup, SizeGB:diskSizeGb, SKU:sku.name, Created:timeCreated}" \
--output table
If you manage many subscriptions, Azure Resource Graph is far faster than iterating with the CLI:
az graph query -q "
Resources
| where type =~ 'microsoft.compute/disks'
| where properties.diskState == 'Unattached'
| project name, resourceGroup, subscriptionId, sizeGb = properties.diskSizeGB, sku = sku.name, created = properties.timeCreated
| order by sizeGb desc
"
Step 2: Snapshot anything worth keeping
Before deleting, take a snapshot. Snapshots are cheaper than full disks because they're incremental and stored on standard storage, so this is a cheap insurance policy.
az snapshot create \
--resource-group myResourceGroup \
--name orphan-disk-20240115-snap \
--source /subscriptions/SUB_ID/resourceGroups/myResourceGroup/providers/Microsoft.Compute/disks/myOrphanDisk \
--incremental true
Tip: Tag your snapshots with a deletion date and the name of the disk they came from. A quick monthly job that purges snapshots past their expiry keeps your safety net from becoming its own cost problem.
Step 3: Delete the disk
Danger: Deleting a managed disk is irreversible. Once it's gone, the only way back is a snapshot you took beforehand. Double check the disk name and resource group, and confirm the disk is genuinely unattached and not in a Reserved state tied to a deallocated VM you still need.
az disk delete \
--resource-group myResourceGroup \
--name myOrphanDisk \
--yes
Doing it in the portal
- Go to Disks in the Azure portal.
- Add the Disk state column, or filter the list by it.
- Select disks showing Unattached.
- For anything important, open the disk and use Create snapshot first.
- Select the disks and click Delete, then confirm.
How to prevent it from happening again
Cleaning up once is easy. Keeping the list empty is the real goal, and that means catching disks before they become forgotten.
Delete data disks with the VM
By default, deleting a VM does not delete its attached data disks. When you create VMs, set the delete option so disks go away with the VM. In Bicep:
{
"storageProfile": {
"osDisk": {
"deleteOption": "Delete"
},
"dataDisks": [
{
"lun": 0,
"createOption": "Attach",
"deleteOption": "Delete",
"managedDisk": {
"id": "[resourceId('Microsoft.Compute/disks', 'myDataDisk')]"
}
}
]
}
}
The same applies in Terraform with delete_data_disks_on_termination behavior controlled through your disk attachment lifecycle, so plan deletes explicitly rather than leaving disks behind.
Enforce with Azure Policy
You can't directly block a disk from becoming unattached, but you can tag disks and audit on the tag. A more practical approach is a scheduled cleanup combined with monitoring. Use a deny policy to require an owner tag on all disks so orphans can always be traced back to a team:
{
"if": {
"allOf": [
{ "field": "type", "equals": "Microsoft.Compute/disks" },
{ "field": "tags['owner']", "exists": "false" }
]
},
"then": { "effect": "deny" }
}
Run a scheduled cleanup
An Azure Automation runbook or a scheduled GitHub Actions / Azure DevOps job can find disks that have been unattached for more than N days and snapshot then delete them. A simple version:
# Find disks unattached and older than 30 days, snapshot then flag for review
az graph query -q "
Resources
| where type =~ 'microsoft.compute/disks'
| where properties.diskState == 'Unattached'
| where todatetime(properties.timeCreated) < ago(30d)
| project id, name, resourceGroup
"
Tip: Wire the Lensix check into your alerting so a new unattached disk creates a ticket the day it appears, not three months later when finance asks about the bill. Catching it early means the person who detached it still remembers why.
Best practices
- Tag everything. Require an owner and an environment tag on every disk so orphans are never anonymous.
- Snapshot before delete, always. Incremental snapshots are cheap and turn an irreversible mistake into a recoverable one.
- Set
deleteOption: Deleteon data disks in your IaC so disks don't outlive their VMs by accident. - Encrypt disks at rest with customer-managed keys where you handle sensitive data. If an orphaned disk does get exported, encryption limits the blast radius.
- Review weekly, not yearly. A short feedback loop keeps the count near zero, which makes each cleanup trivial instead of a multi-thousand-dollar archaeology project.
- Apply least privilege to disk operations. Restrict who can create snapshots and generate SAS URIs, since those are the two actions an attacker would use to exfiltrate data from an unattached disk.
Unattached disks are the kind of problem that's invisible until you go looking. Once you have a habit of checking and a policy that ties every disk to an owner, they stop accumulating, and both your bill and your attack surface get smaller.

