Default NSG Inbound Rule Silently Allows Lateral Traffic Across an Entire Azure Virtual Network
An Azure NSG that looks locked down can still allow unrestricted traffic between hosts in the same virtual network, because a non-removable default rule permitting VNet-sourced traffic is never overridden by deny rules aimed only at internet ranges.
Operational summary
At a glance
- Symptom
- Traffic that should be blocked by a locked-down network security group still reaches a virtual machine from other hosts inside the same virtual network.
- Likely cause
- Azure network security groups ship with default rules that cannot be deleted and that sit at the bottom of the rule evaluation order, so…
- Impact
- A compromised or misconfigured host anywhere else in the same virtual network — or in a peered virtual network where the VirtualNetwork service tag has been allowed to…
- Verification signal
- Validation must show that the new rule blocks unapproved intra-VNet traffic while leaving every dependency the diagnosis step identified still functioning.
- Safe correction
- Add an explicit custom rule that denies or scopes down inbound traffic sourced from the VirtualNetwork tag, at a priority number lower than the default allow rule, restricted…
- Rollback or recovery
- If the new rule blocks a dependency that diagnosis missed, remove it immediately and restore the prior behaviour rather than attempting a live patch under pressure.
Symptom
Traffic that should be blocked by a locked-down network security group still reaches a virtual machine from other hosts inside the same virtual network. A platform team applies what looks like a restrictive Azure NSG — deny rules for inbound internet ranges, no explicit allow entries for peer subnets — and yet a penetration test, or an incident investigation after a compromised host, shows that a different virtual machine on another subnet in the same VNet can still open a connection to the “protected” host on ports the team never explicitly opened.
False Assumption
The team assumes that an NSG populated only with deny rules for external ranges, plus the platform default posture, fully isolates the subnet from every other resource in the environment, including other virtual machines inside the same virtual network. In practice, the NSG’s own non-removable default rule set continues to permit traffic that originates from within the virtual network unless a custom rule is added with a priority number lower than that default rule, explicitly overriding it.
Root Cause
Azure network security groups ship with default rules that cannot be deleted and that sit at the bottom of the rule evaluation order, so they only take effect when no custom rule matches first. Among those defaults is a rule that allows inbound traffic sourced from anywhere inside the virtual network, alongside a rule permitting Azure Load Balancer health-probe traffic. Custom rules are evaluated first, in ascending priority-number order, and only fall back to the defaults when nothing else matches. If every custom rule an engineer writes targets internet-sourced address ranges — because that is the traffic the team is worried about — the default VNet-allow rule is never touched, never overridden and therefore never actually inspected during a rule review. The NSG looks deliberately restrictive because of the custom deny entries, but the review has silently skipped the one default rule doing most of the permissive work.
Impact
A compromised or misconfigured host anywhere else in the same virtual network — or in a peered virtual network where the VirtualNetwork service tag has been allowed to expand across the peering — can reach the supposedly protected host directly, without passing through any internet-facing boundary at all. This converts a single compromised workload into a pivot point for lateral movement across the estate, and it does so in a way that a superficial custom-rule listing will not reveal, because the permissive behaviour comes from a default rule rather than from anything an engineer wrote and can find in a change log.
Diagnosis
Confirm the gap with read-only checks before changing anything. List the custom rules on the affected NSG and confirm whether any rule explicitly targets the VirtualNetwork source tag with a priority number lower than the platform default. Then retrieve the effective security rules on the network interface itself, which merges subnet-level and NIC-level NSGs with the default rule set and shows what traffic is actually permitted, rather than what a single NSG’s custom rule list implies.
Read-only checks
az network nsg rule list --resource-group <rg> --nsg-name <nsg> -o table— confirms whether any custom rule already addresses VNet-sourced traffic.az network nic show-effective-network-security-group --name <nic> --resource-group <rg>— returns the merged rule set actually applied to the interface, including the default VNet-allow rule if nothing overrides it.
Evidence to look for: the effective rule set includes an allow entry for source VirtualNetwork with no matching custom deny rule positioned ahead of it.
Correction
Add an explicit custom rule that denies or scopes down inbound traffic sourced from the VirtualNetwork tag, at a priority number lower than the default allow rule, restricted to only the subnets, application security groups or hosts that genuinely need to communicate. Do not attempt a single blanket deny-everything-from-VirtualNetwork rule across a shared NSG without first identifying every legitimate intra-VNet dependency — domain controller replication, management-plane access, monitoring agents and load-balancer health probes commonly rely on that default path.
State-changing command
az network nsg rule create --resource-group <rg> --nsg-name <nsg> --name DenyVNetInboundExceptApproved --priority 200 --direction Inbound --access Deny --protocol '*' --source-address-prefixes VirtualNetwork --destination-address-prefixes <scoped-subnet-or-asg> --destination-port-ranges '*'
This creates a scoped, reversible override; it does not delete or replace any existing rule.
Validation
Validation must show that the new rule blocks unapproved intra-VNet traffic while leaving every dependency the diagnosis step identified still functioning. Re-run the effective security rules query on the target NIC and confirm the new deny rule now appears ahead of the default VNet-allow rule in the merged list. Attempt a connection from an unapproved host on another subnet in the same VNet and confirm it is refused, then separately confirm that approved flows — replication, monitoring, health probes — still succeed from their expected sources.
Rollback
If the new rule blocks a dependency that diagnosis missed, remove it immediately and restore the prior behaviour rather than attempting a live patch under pressure. Run az network nsg rule delete --resource-group <rg> --nsg-name <nsg> --name DenyVNetInboundExceptApproved to remove the override and revert to the previous effective rule set, then re-confirm the previously broken dependency recovers before re-attempting a narrower rule.
Prevention
Treat the default VNet-allow rule as a rule that must be reviewed on every NSG, not as background platform behaviour that can be ignored because it was never authored by the team. Include effective security rules output, not just custom rule listings, in every network security review and change approval. Where subnets host workloads with different trust levels, use application security groups to scope intra-VNet allow paths explicitly rather than relying on the blanket default remaining acceptable indefinitely.
Apply the safer control
Before you change production
Confirm the affected scope, export the current configuration, and test the replacement control in a non-production environment first.
Fix commands and configuration
az network nsg rule list --resource-group <rg> --nsg-name <nsg> -o tableaz network nic show-effective-network-security-group --name <nic> --resource-group <rg>az network nsg rule create --resource-group <rg> --nsg-name <nsg> --name DenyVNetInboundExceptApproved --priority 200 --direction Inbound --access Deny --protocol '*' --source-address-prefixes VirtualNetwork --destination-address-prefixes <scoped-subnet-or-asg> --destination-port-ranges '*'Verify, roll back or escalate
Verify
Validation must show that the new rule blocks unapproved intra-VNet traffic while leaving every dependency the diagnosis step identified still functioning.
Rollback
If the new rule blocks a dependency that diagnosis missed, remove it immediately and restore the prior behaviour rather than attempting a live patch under pressure.
Escalate
Escalate when the blast radius is uncertain, the control cannot be tested safely, or remediation requires an outage or security exception.