What it is
A network security group (NSG) whose subnets and networkInterfaces arrays are both empty. It has rules, but nothing is attached to it, so none of those rules apply to anything. It is a free resource, so it lingers in inventory indefinitely.
Why it happens
NSGs are created and detached constantly during network churn: a subnet is re-architected, a NIC is deleted with its VM, an NSG is swapped for a newer one. Azure does not delete the old NSG, and since it carries no charge, nothing prompts a cleanup.
The trap is that an orphaned NSG still looks like a control. Its rules remain readable and editable, so someone can "harden" nsg-web-legacy believing they are tightening security, when the NSG governs zero resources. Over time these detached policies drift out of sync with the ones actually in force.
What it costs / blast radius
Nothing on the bill. The harm is security hygiene and governance: an orphaned NSG is dead configuration that misleads audits. Anyone reviewing your rule set has to work out which NSGs are live and which are decorative, and a change made to a detached NSG produces a false sense of protection. The more of them accumulate, the harder it is to reason about what your network actually allows. (Authored assessment of Azure behavior, not a measured statistic.)
See it
Resources
| where type =~ 'microsoft.network/networkSecurityGroups'
| where array_length(coalesce(properties.subnets, dynamic([]))) == 0
and array_length(coalesce(properties.networkInterfaces, dynamic([]))) == 0
| project name, resourceGroup, subscriptionId, location,
ruleCount = array_length(properties.securityRules)// Both subnets and networkInterfaces empty means it protects nothing.
az network nsg show --name nsg-web-legacy --resource-group rg-net \
--query "{subnets:subnets, nics:networkInterfaces}"
az network nsg delete --name nsg-web-legacy --resource-group rg-netHow StratoLens helps
StratoLens inventories every network security group across every subscription in your own tenant and flags the ones associated with nothing, so detached policies stop masquerading as active controls. Continuously and automatically, which keeps your live rule set legible when it matters for an audit.