This check flags Azure Network Security Group rules that allow inbound SMTP (port 25) from the public internet. Exposed SMTP turns your VMs into spam relay targets and often leads to outbound mail being blocked by Azure. Restrict the source to known mail relays or remove the rule entirely.
Port 25 is one of those ports that sticks around in network rules long after anyone remembers why it was opened. Maybe a VM ran Postfix during a migration, or someone copied an NSG template from a Stack Overflow answer. Either way, an NSG rule that allows SMTP from 0.0.0.0/0 (or Azure's Internet service tag) is a liability, and the nsg_opensmtp check exists to catch it before someone else does.
What this check detects
The check scans every Network Security Group in your subscription and looks for inbound security rules that meet all of these conditions:
- Direction is
Inbound - Access is
Allow - Protocol is TCP (or
*) - Destination port includes 25, either directly, as part of a range, or via a wildcard
- Source is a public address, meaning
0.0.0.0/0,*, or theInternetservice tag
If a rule matches, Lensix raises a finding against that NSG. SMTP on port 25 is plaintext by default and carries no authentication at the network layer, so any host on the internet that can reach the port can attempt to talk to whatever is listening behind it.
Note: Port 25 is the classic server-to-server mail transfer port. Modern mail submission from clients uses port 587 (with STARTTLS) or 465 (implicit TLS). If you see port 25 open to the internet on a general-purpose VM, it is almost always a mistake rather than a real mail server.
Why it matters
An open SMTP port is not just a checkbox failure. It maps to concrete, expensive problems.
1. Open relay and spam abuse
If a misconfigured mail daemon is listening behind that port, attackers will find it through automated scanning and use it to relay spam. Spammers actively scan IPv4 space for open port 25 because a working relay is a free, disposable sending platform. Once your VM's public IP starts sending spam, it lands on blocklists like Spamhaus, and any legitimate mail from that IP stops being delivered.
2. Reputation damage on shared Azure IP space
Azure public IPs are recycled. If your VM gets blocklisted while abusing port 25, the next tenant who inherits that IP starts with a poisoned reputation. Microsoft takes this seriously, which is why outbound port 25 is throttled or blocked on most Azure subscriptions by default.
Warning: Azure blocks outbound TCP 25 for most subscription types created after late 2017, and for many MSDN and trial subscriptions entirely. Even if you intend to run a real mail server, you generally cannot send mail directly on port 25 without going through a managed relay like SendGrid, Mailgun, or Amazon SES. An open inbound port 25 rule with no working outbound path is almost always pure exposure with zero benefit.
3. Reconnaissance and exploitation
Even without an open relay, an exposed SMTP service leaks information. Banner grabbing reveals the mail software and version, which helps attackers fingerprint your stack and look for known CVEs. VRFY and EXPN commands on older configs can enumerate valid user accounts. None of this is information you want handed to anyone who runs a port scan.
How to fix it
The fix is to stop allowing port 25 from the public internet. You have three realistic options, in order of preference.
Step 1: Find the offending rule
List inbound rules across an NSG and spot anything touching port 25 from a public source:
az network nsg rule list \
--resource-group my-rg \
--nsg-name my-nsg \
--query "[?direction=='Inbound' && access=='Allow' && (destinationPortRange=='25' || destinationPortRange=='*')].{name:name, port:destinationPortRange, source:sourceAddressPrefix}" \
--output table
Step 2a: Delete the rule (best option)
If nothing on this VM is supposed to receive internet mail, just remove the rule.
Danger: Deleting an NSG rule changes live network behavior immediately. Confirm no production traffic depends on inbound port 25 before running this. For a true mail server, deleting this rule will stop inbound mail delivery.
az network nsg rule delete \
--resource-group my-rg \
--nsg-name my-nsg \
--name allow-smtp-inbound
Step 2b: Restrict the source to known relays
If you genuinely need to receive mail from a specific upstream relay or a partner system, narrow the source from Internet to that explicit address range.
az network nsg rule update \
--resource-group my-rg \
--nsg-name my-nsg \
--name allow-smtp-inbound \
--source-address-prefixes 203.0.113.0/24 \
--destination-port-ranges 25
Step 2c: Use a managed mail service instead
For outbound mail, route through a managed provider so you never expose or rely on raw port 25. This removes the need for the inbound rule entirely in most architectures and sidesteps Azure's outbound port 25 block.
Tip: If your application only needs to send email, you do not need any inbound SMTP rule at all. Use Azure Communication Services Email, SendGrid, or another API-based provider over HTTPS (port 443), and close port 25 completely.
Fixing it in Terraform
If your NSGs are managed as code, fix the source there so the change does not get reverted on the next apply. Replace the wildcard source with a specific prefix, or remove the rule block:
resource "azurerm_network_security_rule" "smtp" {
name = "allow-smtp-inbound"
priority = 200
direction = "Inbound"
access = "Allow"
protocol = "Tcp"
source_port_range = "*"
destination_port_range = "25"
# Before: source_address_prefix = "Internet" # flagged
source_address_prefix = "203.0.113.0/24" # known relay only
destination_address_prefix = "*"
resource_group_name = azurerm_resource_group.main.name
network_security_group_name = azurerm_network_security_group.main.name
}
How to prevent it from happening again
A one-time fix is worthless if the next Terraform module or manual change reopens the port. Bake the guardrail into your pipeline and platform.
Azure Policy as a deny gate
Azure Policy can block the creation of NSG rules that allow port 25 from the internet. Use a policy with a deny effect that matches inbound allow rules on port 25 with broad sources:
{
"if": {
"allOf": [
{ "field": "type", "equals": "Microsoft.Network/networkSecurityGroups/securityRules" },
{ "field": "Microsoft.Network/networkSecurityGroups/securityRules/direction", "equals": "Inbound" },
{ "field": "Microsoft.Network/networkSecurityGroups/securityRules/access", "equals": "Allow" },
{ "field": "Microsoft.Network/networkSecurityGroups/securityRules/destinationPortRange", "equals": "25" },
{ "anyOf": [
{ "field": "Microsoft.Network/networkSecurityGroups/securityRules/sourceAddressPrefix", "equals": "*" },
{ "field": "Microsoft.Network/networkSecurityGroups/securityRules/sourceAddressPrefix", "equals": "Internet" },
{ "field": "Microsoft.Network/networkSecurityGroups/securityRules/sourceAddressPrefix", "equals": "0.0.0.0/0" }
]}
]
},
"then": { "effect": "deny" }
}
Catch it in CI before deploy
Run a static scan against your IaC in the pull request so the bad rule never reaches Azure. Tools like Checkov, tfsec, and Terrascan all flag public SMTP exposure. A minimal pipeline step:
# Fails the build if any high-severity NSG misconfig is found
checkov -d ./infra --framework terraform --compact
Tip: Pair the deny policy with continuous detection in Lensix. Policy stops new bad rules, and Lensix catches drift, rules created outside your IaC, and anything that predates the policy. The two layers cover each other's gaps.
Best practices
- Default deny on inbound. Start NSGs from a closed posture and open only the specific ports and sources each workload requires.
- Never use
Internetor*as a source for service ports. Reserve broad sources for genuinely public services like HTTPS load balancers, and even then prefer fronting them with a WAF. - Prefer managed email over self-hosted SMTP. Running your own mail server on Azure means fighting the outbound port 25 block, managing TLS, SPF, DKIM, and DMARC, and owning IP reputation. A managed provider removes all of that.
- Use service tags and ASGs. Application Security Groups let you scope rules to workloads by identity rather than IP ranges, which keeps rules readable and harder to misconfigure.
- Audit NSGs on a schedule. Rules accumulate. Periodic review, ideally automated, catches the orphaned port 25 rule from a project that shipped two years ago.
- Enable NSG flow logs. If port 25 is exposed, flow logs tell you whether anything is actually hitting it, which informs how urgently you respond.
The bottom line: there is almost no scenario where a general-purpose Azure VM should accept SMTP from the entire internet. Close the port, route mail through a managed service, and put a policy gate in front of your pipeline so the rule cannot come back.

