This check flags GCP firewall rules that allow inbound traffic to SQL Server (port 1433) from 0.0.0.0/0. An exposed database port invites brute-force and exploit attacks against your data layer. Fix it by scoping the source range to known IPs or removing public access entirely and routing through a bastion or private connectivity.
SQL Server should almost never listen on the public internet. Yet exposed port 1433 rules show up constantly in GCP environments, usually because someone needed quick access during setup and never tightened the rule. This Lensix check, vpc_opensqlserver in the vpc_checks module, catches firewall rules that open TCP port 1433 to public source ranges before an attacker does.
What this check detects
The check inspects your VPC firewall rules and flags any ingress allow rule that meets all of these conditions:
- Direction is
INGRESS - Action is
ALLOW - The rule permits TCP port
1433(either directly, as part of a range, or via an "all ports" rule) - The source range includes
0.0.0.0/0(IPv4) or::/0(IPv6)
Port 1433 is the default TCP port for Microsoft SQL Server. When a firewall rule opens it to the world, anyone on the internet can attempt to reach your database engine, whether it runs on a Compute Engine VM, in a container, or anywhere else inside that VPC.
Note: GCP firewall rules apply at the network level based on target tags, service accounts, or the whole VPC. A single overly broad rule can expose every VM that matches its target, not just the one you were thinking about when you wrote it.
Why it matters
A database port on the public internet is one of the highest-value targets an attacker can find. Here is what tends to happen once it is exposed.
Automated scanning finds it within minutes
Mass scanners like those feeding Shodan and Censys sweep the entire IPv4 space continuously. A newly opened 1433 port gets discovered and catalogued fast, often before you have finished configuring the server. Once it is in a scan database, it stays on attacker target lists.
Credential brute-forcing
SQL Server authentication, particularly the built-in sa account when SQL authentication is enabled, is a favorite target. Bots hammer weak or default credentials around the clock. A successful login often leads to enabling xp_cmdshell and running operating system commands on the host, which turns a database breach into full host compromise.
Exploitation of unpatched servers
SQL Server has a history of remotely exploitable CVEs. If your instance lags on patches, an exposed port is a direct path to remote code execution without needing any credentials at all.
Danger: A compromised SQL Server frequently means a full data breach. Attackers exfiltrate tables wholesale, deploy ransomware against the data, and pivot to other systems using the credentials and network access the host provides. The blast radius rarely stops at one database.
Compliance failures
PCI DSS, HIPAA, SOC 2, and CIS GCP Benchmark all explicitly require that database ports not be reachable from the public internet. An open 1433 rule is a finding in any audit that touches network controls.
How to fix it
Start by finding the offending rules, then decide whether to scope them down or remove them.
Step 1: Identify the rule
List firewall rules that allow port 1433 from anywhere:
gcloud compute firewall-rules list \
--filter="direction=INGRESS AND sourceRanges:0.0.0.0/0" \
--format="table(name, network, sourceRanges.list(), allowed[].map().firewall_rule().list())"
Inspect a specific rule to confirm it opens 1433:
gcloud compute firewall-rules describe RULE_NAME --format=json
Step 2: Scope the source range
If a specific set of trusted IPs genuinely needs database access, replace the public range with those addresses. Never leave it as 0.0.0.0/0.
gcloud compute firewall-rules update RULE_NAME \
--source-ranges="203.0.113.10/32,198.51.100.0/24"
Warning: Updating --source-ranges replaces the entire list, it does not append. Include every IP that should keep access in a single command, or you will lock out legitimate clients.
Step 3: Remove the rule entirely if no one needs public access
In most architectures the right answer is no public access at all. Database traffic should stay inside the VPC.
Danger: Deleting a firewall rule can immediately cut off live connections. Confirm that no application or admin path depends on this rule before running the command below, ideally during a maintenance window.
gcloud compute firewall-rules delete RULE_NAME
Step 4: Provide a safe access path instead
Teams open 1433 publicly because they need a way in. Give them a better one so the public rule does not creep back:
- IAP for TCP forwarding lets admins reach the SQL port over an authenticated tunnel with no public IP at all.
- Cloud SQL with private IP keeps the managed instance off the public internet entirely.
- A bastion host in a private subnet, reachable only via IAP or VPN.
Example IAP-based firewall rule that allows 1433 only from Google's IAP range, targeting tagged hosts:
gcloud compute firewall-rules create allow-sqlserver-iap \
--direction=INGRESS \
--action=ALLOW \
--rules=tcp:1433 \
--source-ranges=35.235.240.0/20 \
--target-tags=sql-server
Then connect through the tunnel:
gcloud compute start-iap-tunnel INSTANCE_NAME 1433 \
--local-host-port=localhost:1433 \
--zone=ZONE
Tip: The 35.235.240.0/20 range belongs to Google's IAP service. Only requests that pass IAP authentication arrive from it, so this rule gives you SQL access without exposing the port to the internet.
How to prevent it from happening again
One-off fixes do not stick. Bake the rule into your pipeline and policy layer so a public 1433 rule cannot be merged or deployed.
Define firewall rules in Terraform
Manage rules as code so they go through review. A scoped rule looks like this:
resource "google_compute_firewall" "sqlserver_iap" {
name = "allow-sqlserver-iap"
network = google_compute_network.main.name
direction = "INGRESS"
allow {
protocol = "tcp"
ports = ["1433"]
}
source_ranges = ["35.235.240.0/20"]
target_tags = ["sql-server"]
}
Gate it in CI/CD with policy-as-code
Use a tool like Open Policy Agent or Checkov to fail the build when a plan opens 1433 to the world. An OPA rule against Terraform plan JSON:
package firewall
deny[msg] {
rule := input.resource_changes[_]
rule.type == "google_compute_firewall"
rule.change.after.direction == "INGRESS"
some r
rule.change.after.allow[r].ports[_] == "1433"
rule.change.after.source_ranges[_] == "0.0.0.0/0"
msg := sprintf("Firewall %q exposes SQL Server port 1433 to 0.0.0.0/0", [rule.change.after.name])
}
Tip: Checkov ships a built-in check for this pattern. Add checkov -d . --compact to your pipeline and it flags public database ports without you writing custom policy.
Enforce an org policy guardrail
Use a hierarchical firewall policy or the compute.vmExternalIpAccess org policy constraint to limit where public exposure is even possible. Combine that with continuous monitoring in Lensix so a drift from console clicks or emergency changes gets caught the same day, not at the next audit.
Best practices
- Default to private. Databases should never have a public IP or a public firewall rule unless there is a documented, reviewed reason.
- Use target tags or service accounts, not broad targets. Scope every rule to the smallest set of hosts that need it.
- Prefer managed connectivity. Cloud SQL private IP, IAP tunnels, and VPN remove the need for internet-facing ports.
- Audit non-default ports too. SQL Server can run on custom ports. Do not assume 1433 is the only one to watch.
- Disable SQL authentication where possible. Use Windows or Azure AD style authentication and never leave the
saaccount enabled with a weak password. - Review rules on a schedule. Temporary access rules have a way of becoming permanent. Track and expire them.
Closing port 1433 to the public is a small change with an outsized payoff. It removes your data layer from the constant background noise of internet scanning and forces attackers back to paths you actually control.

