This check flags GCP firewall rules that open wide port ranges instead of the specific ports a workload actually needs. Wide ranges expose unused services to lateral movement and scanning. Fix it by replacing the range with an explicit list of required ports.
Firewall rules are supposed to be a tight contract: this source can reach these ports on these targets. But it is surprisingly easy to write a rule that says "allow everything from 1 to 65535" when all you needed was port 443. The Lensix check Firewall Rule Allows Large Port Range (vpc_portrangerule) catches exactly that pattern in your GCP VPC firewall configuration.
A wide port range is not a vulnerability by itself, but it removes a layer of defense you paid for. When something else goes wrong, an exposed SSH daemon, a forgotten admin panel, a database listening on its default port, the firewall is the thing that should have stopped the connection. A rule that allows 1-65535 stops nothing.
What this check detects
The check inspects every allow firewall rule in your GCP projects and looks at the ports field for each protocol. It raises a finding when a rule permits a port range that is broader than necessary, for example a contiguous span like 0-65535, 1-1000, or any large block that clearly covers more ports than a single service would use.
A typical offending rule looks like this when you describe it:
{
"name": "allow-internal-wide",
"network": "default",
"direction": "INGRESS",
"sourceRanges": ["10.0.0.0/8"],
"allowed": [
{
"IPProtocol": "tcp",
"ports": ["0-65535"]
}
]
}
The tcp:0-65535 entry is the problem. It allows traffic to every TCP port on every target instance the rule applies to. Even when the source is an internal range, that is far more access than most workloads require.
Note: In GCP, a firewall rule with no ports specified for a protocol allows all ports for that protocol. So allowed: [{ "IPProtocol": "tcp" }] with no ports is just as wide as tcp:0-65535. This check treats both cases as overly permissive.
Why it matters
The principle here is least privilege applied to the network. A firewall rule should expose the smallest set of ports needed for a service to function, and nothing more. When you open a large range, you create several concrete problems.
Lateral movement gets easier
Most real breaches do not stop at the first compromised host. An attacker who lands on one instance, through a leaked credential or a vulnerable app, will scan the internal network for anything reachable. If your internal firewall rules allow tcp:0-65535 between subnets, every service on every VM is a candidate target: SSH on 22, RDP on 3389, Redis on 6379, Postgres on 5432, internal admin dashboards on random high ports. A tight rule that only allows the ports an app actually serves would have blocked most of those probes.
Forgotten services stay exposed
Teams spin up debugging endpoints, metrics exporters, and management interfaces all the time. Many of these bind to high ports and are never meant to be reachable beyond localhost. A wide firewall range silently exposes all of them. You end up with an attack surface nobody is tracking because the firewall was never the control that limited it.
Warning: Wide ranges combined with a broad sourceRanges of 0.0.0.0/0 are the worst case. That combination exposes every port on the target instances to the entire internet. If you find a rule like that on a public-facing network tag, treat it as an active incident, not a backlog item.
Compliance and audit friction
CIS Benchmarks for GCP, PCI DSS, and most internal security baselines expect firewall rules to be scoped to specific ports. A blanket range is an obvious finding in any audit, and "we never got around to tightening it" is not a great answer to give an assessor.
How to fix it
Fixing the rule means replacing the wide range with the explicit ports your workload needs. The steps below walk through identifying the rule, confirming what it should allow, and updating it.
1. Find the offending rules
List all firewall rules and inspect their allowed ports:
gcloud compute firewall-rules list \
--format="table(name, network, direction, allowed[].map().firewall_rule().list(), sourceRanges.list())"
To pull the full detail for a single rule:
gcloud compute firewall-rules describe allow-internal-wide --format=json
2. Determine the ports the workload actually needs
Before you narrow anything, confirm what the target instances genuinely serve. Check the listening ports on a representative VM:
# On the instance
sudo ss -tlnp
Cross-reference that with what your application is supposed to expose. A web tier usually needs 80 and 443. A database tier might need 5432 or 3306 from the app subnet only. Resist the urge to keep a range "just in case", that defeats the entire purpose.
3. Update the rule to specific ports
Danger: Narrowing a firewall rule can break live traffic if you remove a port something depends on. Verify the required ports first, and where possible test the change in a staging project or during a maintenance window. Updating a rule applies immediately to all matching instances.
Replace the wide range with an explicit allow list:
gcloud compute firewall-rules update allow-internal-wide \
--allow=tcp:443,tcp:8080 \
--source-ranges=10.0.0.0/8
If the original rule mixed protocols, list each one explicitly:
gcloud compute firewall-rules update allow-internal-wide \
--allow=tcp:443,tcp:8080,udp:53
For a rule that should not exist at all, delete it rather than narrow it:
gcloud compute firewall-rules delete allow-internal-wide
4. Verify the change
gcloud compute firewall-rules describe allow-internal-wide \
--format="value(allowed)"
Confirm the output shows only the ports you intended, then validate that the workload still serves traffic on those ports.
Tip: Enable Firewall Rules Logging on the rule before you tighten it. Run it for a few days, then query the logs in Cloud Logging to see exactly which ports and sources are actually being used. That turns a guessing game into a data-driven change.
gcloud compute firewall-rules update allow-internal-wide \
--enable-logging
Fixing it in Terraform
If your firewall rules live in Terraform, change them at the source so the next apply does not undo your console fix. A scoped google_compute_firewall resource looks like this:
resource "google_compute_firewall" "allow_web" {
name = "allow-web"
network = google_compute_network.main.name
direction = "INGRESS"
source_ranges = ["10.0.0.0/8"]
target_tags = ["web"]
allow {
protocol = "tcp"
ports = ["443", "8080"]
}
}
Avoid patterns like ports = ["0-65535"] or omitting ports entirely unless the protocol genuinely has no concept of ports (such as ICMP). Pin every TCP and UDP rule to an explicit list.
How to prevent it from happening again
One-off fixes drift back over time. The durable solution is to make wide port ranges fail before they reach production.
Policy-as-code with OPA
If you run terraform plan through CI, a Rego policy can reject any rule that opens a large range. A simple Conftest rule:
package main
deny[msg] {
rule := input.resource_changes[_]
rule.type == "google_compute_firewall"
allow := rule.change.after.allow[_]
port := allow.ports[_]
contains(port, "-")
parts := split(port, "-")
to_number(parts[1]) - to_number(parts[0]) > 100
msg := sprintf("Firewall rule %s opens a port range wider than 100 ports: %s", [rule.change.after.name, port])
}
Wire that into your pipeline so a merge cannot land a rule that fails the check.
Organization Policy constraints
At the platform level, you can use a custom Organization Policy constraint to block firewall rules with overly broad ranges across every project, so individual teams cannot opt out.
Tip: Pair the CI gate with continuous monitoring in Lensix. The pipeline catches new rules before merge, and the vpc_portrangerule check catches anything created out-of-band through the console or the API. Together they close both ends of the gap.
Best practices
- Name ports, not ranges. Default to an explicit allow list and only use a range when a service genuinely needs contiguous ports, such as a passive FTP data range.
- Scope the source too. A tight port range with
0.0.0.0/0as the source is still risky. Combine narrow ports with narrow source ranges and target tags. - Use target tags or service accounts. Apply rules to specific instance groups rather than the whole network, so the blast radius of any single rule stays small.
- Turn on Firewall Rules Logging for rules that protect sensitive workloads, so you have evidence of what is actually connecting.
- Review rules on a schedule. Firewall config rots. A quarterly review against your IaC source catches drift and orphaned rules before they become audit findings.
- Prefer deny-by-default. GCP networks deny inbound traffic by default. Lean on that and add the minimum allow rules you need, rather than opening wide and trimming later.
A firewall rule scoped to the exact ports a service uses costs nothing extra and gives you a real control to fall back on when something else fails. Wide ranges trade that protection away for a few minutes of saved typing. This check exists to make sure you do not make that trade by accident.

