Firewall rules exposing SSH, RDP, or database ports to 0.0.0.0/0
What does ZopNight detect here?
Firewall rules admitting 0.0.0.0/0 to any of 11 sensitive ports (SSH 22, RDP 3389, WinRM 5985/5986, MySQL 3306, PostgreSQL 5432, MSSQL 1433, MongoDB 27017, Redis 6379, Telnet 23, FTP 21) are flagged critical by RC-134. Internet scanners find such openings within minutes of creation.
Signal and threshold
| Field | Value |
|---|---|
| Rule IDs | RC-134 |
| Category | compliance |
| Severity | critical |
| Metric | none — pure configuration read |
| Source | firewall_public.go |
Where it applies
Eleven ports scanners try first
ZopNight’s discoverer classifies a specific port list as sensitive: the remote-management set of SSH 22, RDP 3389, WinRM 5985 and 5986; the datastore set of MySQL 3306, PostgreSQL 5432, MSSQL 1433, MongoDB 27017 and Redis 6379; and the legacy-cleartext pair, Telnet 23 and FTP 21. These are the ports where reachability alone is most of the compromise: management ports invite brute-force against real login surfaces, datastore ports frequently front services deployed with weak or default authentication, and the cleartext protocols leak credentials to any on-path observer by design.
Minutes from creation to first probe
Exposure here is not theoretical drift. The internet is continuously enumerated. Services like Shodan and the botnets running their own scans typically touch a newly opened port within minutes, and an SSH daemon on a public IP collects automated login attempts more or less immediately and indefinitely. A rule like this created “just for today’s debugging” is being actively tested against long before it is remembered and removed.
Both flags must agree before RC-134 fires
The discoverer derives two markers from each firewall rule’s allowed[],
sourceRanges[], direction, and disabled fields: one saying the rule is an enabled
ingress allow from 0.0.0.0/0 or ::/0, one saying a sensitive port is among what it
admits. RC-134 fires only when both read explicitly true, and abstains when either is
absent. An internal-only rule on port 22, or an internet-facing rule on port 443 alone,
never fires. Detection is proven from provider config, read via Cloud Asset Inventory
under roles/cloudasset.viewer, and the finding is informational only.
Ranges count too
A rule does not need to name a sensitive port to expose one. The classifier expands every
ports[] token, so a span like 1000-4000 is flagged because 3306 sits inside it, and a
tcp entry with no ports at all, meaning every port, is sensitive by inclusion. Reviewing
rules by eye misses these; the enumeration does not.
Find the exposures in your project
gcloud compute firewall-rules list \ --filter="direction=INGRESS AND disabled=false AND sourceRanges.list():0.0.0.0/0" \ --format="table(name,network,allowed[].map().firewall_rule().list())"Check the output for the eleven ports above, or ranges containing them.
IAP and Auth Proxy instead of open ports
The durable fix removes the need for the opening rather than narrowing it.
Identity-Aware Proxy tunnels SSH and RDP through Google’s front end with per-identity
authorization, leaving no listening port on the instance’s public address. Databases
belong behind Cloud SQL Auth Proxy or private IP with VPC peering. Where a direct rule
must survive, shrink its source to named, owned CIDRs such as an office range or VPN egress,
and treat any remaining 0.0.0.0/0 entry as an incident, not a configuration.