Back to blog
Best PracticesCloud SecurityGCPNetworking

GCP Firewall Allows Public SMTP: Risks and Remediation

Learn why a GCP firewall rule allowing public SMTP on port 25 is risky, how to remediate it with gcloud and Terraform, and how to prevent it with policy-as-code.

TL;DR

This check flags GCP firewall rules that allow inbound SMTP (port 25) from 0.0.0.0/0. Open SMTP invites spam relaying, abuse reports, and IP blacklisting. Restrict the source range to known mail infrastructure or remove the rule entirely.

Port 25 is one of those ports that almost never needs to be open to the entire internet. When Lensix finds a GCP firewall rule allowing SMTP from public sources, it usually means a mail server was set up quickly and locked down later, or a default rule was copied without much thought. Either way, an open port 25 is a liability worth fixing before someone else finds it first.

This post explains what vpc_opensmtp looks for, why a publicly reachable SMTP port is risky, and how to close it down without breaking legitimate mail flow.


What this check detects

The vpc_opensmtp check inspects VPC firewall rules in your GCP project and flags any ingress rule that:

  • Has an action of ALLOW
  • Permits traffic on TCP port 25 (the standard SMTP port), either directly or within a port range
  • Has a source range of 0.0.0.0/0 (any IPv4 address) or ::/0 (any IPv6 address)

A matching rule means anyone on the internet can attempt to open a connection to your mail server's SMTP listener. That is the condition this check is built to surface.

Note: Port 25 is for server-to-server mail transfer (MTA to MTA). Mail submission from clients uses port 587 (with STARTTLS) or 465 (implicit TLS). If you only run mail clients and not a relay, you almost certainly do not need port 25 open to the public at all.


Why it matters

An SMTP port open to the world is a magnet for abuse. Here is what tends to go wrong.

Open relay abuse and spam

If the mail server behind the port is misconfigured as an open relay, attackers will use it to send spam through your infrastructure. Even when the server itself is configured correctly, a publicly exposed port 25 gets hammered by automated relay-testing bots within hours of going live. Every one of those connection attempts is a probe looking for a weakness.

IP reputation damage and blacklisting

This is the business impact that stings the most. If your server relays spam, or even if it just looks like a suspicious open endpoint, your GCP egress IP can land on blocklists like Spamhaus or Barracuda. Once an IP is listed, legitimate mail you send starts bouncing or landing in spam folders, and getting delisted is slow and painful.

Warning: GCP blocks outbound traffic on port 25 by default to protect IP reputation across the platform. An inbound rule that opens port 25 publicly is often paired with workarounds that reintroduce the exact risk Google is trying to prevent.

Reconnaissance and credential attacks

SMTP servers leak information. A simple EHLO exchange reveals the server software, version, and supported extensions. Attackers use this to fingerprint your stack and look for known vulnerabilities. If the server supports VRFY or EXPN, attackers can enumerate valid email addresses. And if authentication is exposed, the port becomes a brute-force target.


How to fix it

The right fix depends on whether you actually need to receive mail from the public internet. Walk through these options in order.

Step 1: Identify the offending rule

List firewall rules that touch port 25:

gcloud compute firewall-rules list \
  --filter="allowed.ports:25 AND direction=INGRESS" \
  --format="table(name, network, sourceRanges.list():label=SRC_RANGES, allowed[].map().firewall_rule().list():label=ALLOW, targetTags.list():label=TARGET_TAGS)"

Look for any rule where the source range is 0.0.0.0/0. Inspect the full definition before changing anything:

gcloud compute firewall-rules describe RULE_NAME --format=yaml

Step 2: Decide whether port 25 is needed at all

Most workloads do not run a public-facing MTA. If nothing in your project legitimately accepts inbound mail from arbitrary senders, delete the rule.

Danger: Deleting a firewall rule is immediate and affects live traffic. Confirm no production mail server depends on this rule before running the command. If a real MTA receives mail through this port, deletion will cause incoming mail to be rejected.

gcloud compute firewall-rules delete RULE_NAME

Step 3: If you need inbound SMTP, scope the source range

If you genuinely run a mail server that must accept connections from specific partners or a managed mail provider, replace the open range with the exact CIDR blocks you trust. Update the existing rule:

gcloud compute firewall-rules update RULE_NAME \
  --source-ranges="203.0.113.0/24,198.51.100.10/32"

For a fresh, tightly scoped rule that only applies to instances tagged mail-server:

gcloud compute firewall-rules create allow-smtp-trusted \
  --network=my-vpc \
  --direction=INGRESS \
  --action=ALLOW \
  --rules=tcp:25 \
  --source-ranges="203.0.113.0/24" \
  --target-tags=mail-server \
  --priority=1000

Step 4: Prefer a managed mail service

Running your own internet-facing MTA is rarely worth the operational burden. Services like SendGrid, Mailgun, Amazon SES, or Google Workspace handle deliverability, reputation, and abuse prevention for you, and they remove the need to expose port 25 at all.

Tip: If you are exposing port 25 only to test outbound delivery, you are solving the wrong problem. Outbound mail does not require an inbound firewall rule. Route outbound mail through a relay on port 587 with authentication and close port 25 entirely.


Fixing it with Infrastructure as Code

If your firewall rules live in Terraform, change them there so the fix does not get reverted on the next apply. A scoped SMTP rule looks like this:

resource "google_compute_firewall" "allow_smtp_trusted" {
  name      = "allow-smtp-trusted"
  network   = google_compute_network.my_vpc.name
  direction = "INGRESS"
  priority  = 1000

  allow {
    protocol = "tcp"
    ports    = ["25"]
  }

  # Never use ["0.0.0.0/0"] here
  source_ranges = ["203.0.113.0/24"]
  target_tags   = ["mail-server"]
}

If the rule exists in state but should be removed, delete the resource block and run terraform apply so the change is tracked rather than done by hand.


How to prevent it from happening again

One-off fixes do not stop the next engineer from copying an open rule. Put guardrails in the path of every change.

Block open SMTP in CI with policy-as-code

An Open Policy Agent / Conftest policy can fail a Terraform plan before it ever reaches GCP. Here is a Rego rule that rejects any firewall allowing port 25 from a public source:

package main

deny[msg] {
  resource := input.resource.google_compute_firewall[name]
  resource.direction == "INGRESS"
  some range
  resource.source_ranges[range] == "0.0.0.0/0"
  some rule
  resource.allow[rule].ports[_] == "25"
  msg := sprintf("Firewall '%s' allows SMTP (port 25) from 0.0.0.0/0", [name])
}

Wire it into your pipeline so a plan with an open SMTP rule fails the build:

terraform plan -out=tfplan.binary
terraform show -json tfplan.binary > tfplan.json
conftest test tfplan.json

Enforce with GCP Organization Policy

For defense at the platform level, GCP organization policies can constrain firewall behavior, and hierarchical firewall policies let you apply guardrails across an entire folder or organization. A hierarchical deny rule for port 25 from public ranges will override permissive project-level rules.

Continuous monitoring

Catch drift that slips past CI. Lensix runs vpc_opensmtp against your live GCP environment on an ongoing basis, so a manually added open rule shows up as a finding instead of sitting unnoticed until it gets abused.


Best practices

  • Default to closed. Open ports to specific CIDR blocks and target tags, never to 0.0.0.0/0 unless the service is genuinely meant for the whole internet (and SMTP almost never is).
  • Use target tags or service accounts. Scope firewall rules to the instances that need them rather than applying broad rules across the VPC.
  • Offload mail to a managed provider. Let a dedicated service own deliverability and abuse handling so you do not have to run a public MTA.
  • Audit firewall rules regularly. Rules accumulate. Review them on a schedule and delete anything with no clear owner or purpose.
  • Log and alert on firewall changes. Send VPC firewall change events from Cloud Audit Logs to your monitoring stack so unexpected rules trigger a notification.
  • Keep IaC as the source of truth. Console-created rules drift and get forgotten. Manage firewall rules in Terraform and let CI enforce policy.

An open SMTP port is a small misconfiguration with an outsized blast radius. Close it, scope future rules tightly, and let automation keep it that way.