Every new GCP project ships with a default VPC that has overly permissive firewall rules and subnets in every region. Delete it and replace it with a purpose-built network: gcloud compute networks delete default (after removing dependent resources).
When you create a Google Cloud project with the Compute Engine API enabled, GCP helpfully provisions a network called default for you. It comes ready to use, with a subnet in every region and a handful of firewall rules so your first VM can reach the internet and accept SSH connections without any setup. Convenient for a demo. A liability for anything real.
This check flags projects where that default VPC still exists. The presence of the network itself is not the whole problem. The problem is what comes attached to it.
What this check detects
The vpc_defaultnetwork check looks for a VPC network named default in the project. GCP creates this automatically unless you explicitly opt out at project creation, and it carries a few default firewall rules that most teams never review:
default-allow-internal— permits all traffic (TCP, UDP, ICMP) between any resources inside the network on the10.128.0.0/9range.default-allow-ssh— allows TCP 22 from0.0.0.0/0, the entire internet.default-allow-rdp— allows TCP 3389 from0.0.0.0/0.default-allow-icmp— allows ICMP from0.0.0.0/0.
The default network is also created in auto mode, which means it automatically generates a subnet in every Google Cloud region, including regions you have no intention of using. That is a lot of address space and a lot of attack surface created without anyone deciding it should exist.
Note: Auto mode networks expand on their own. When Google adds a new region, your auto mode VPC gets a new subnet there automatically. Custom mode networks only have the subnets you explicitly define, which is what you want for any environment you actually care about.
Why it matters
The default firewall rules are the headline risk. default-allow-ssh and default-allow-rdp open management ports to the public internet for every instance in the network. Anyone who spins up a VM in the default network, perhaps a developer testing something quickly, inherits a machine with SSH or RDP exposed to the world.
Internet-facing SSH and RDP get scanned constantly. Automated bots sweep GCP IP ranges looking for exactly these ports, then run credential stuffing and brute-force attacks. A weak password, a reused key, or an unpatched service is all an attacker needs to get a foothold.
The default-allow-internal rule is the quieter risk. It lets every resource in the network talk to every other resource on all ports. If an attacker compromises one instance, lateral movement is trivial. There is no segmentation, no least-privilege between workloads, nothing to slow them down.
Warning: Auto mode subnets in unused regions are easy to forget about. A misconfigured deployment or a compromised service account could launch resources in asia-south2 or southamerica-east1 where you are not monitoring, and the bill (and the breach) would land before anyone notices.
From a compliance standpoint, CIS Google Cloud Foundations Benchmark recommends removing the default network outright (control 3.1). If you are pursuing SOC 2, ISO 27001, or PCI DSS, an auditor who sees a default VPC with public SSH rules is going to ask questions.
How to fix it
The fix is to delete the default network and build a custom mode VPC that only has the subnets and firewall rules you actually need. You cannot delete a network while resources still depend on it, so the order matters.
Step 1: Check what is using the default network
Before deleting anything, find out what lives in it.
# List instances on the default network
gcloud compute instances list \
--filter="networkInterfaces.network:default" \
--format="table(name,zone,networkInterfaces.network)"
# List forwarding rules, then check which use default
gcloud compute forwarding-rules list
# List the firewall rules attached to default
gcloud compute firewall-rules list \
--filter="network=default" \
--format="table(name,sourceRanges.list(),allowed[].map().firewall_rule().list())"
Danger: Deleting a VPC network deletes its subnets, routes, and firewall rules. Any running workload that depends on it will lose connectivity. Migrate or recreate those resources on your new custom VPC first, and run this in a non-production project before touching anything live.
Step 2: Delete the dependent firewall rules
gcloud compute firewall-rules delete \
default-allow-internal \
default-allow-ssh \
default-allow-rdp \
default-allow-icmp \
--quiet
Step 3: Delete the subnets (auto mode)
An auto mode network has a subnet in every region. You can convert it to custom mode first, which is non-destructive, or delete subnets individually. To remove the whole network you do not need to delete subnets manually, since deleting the network removes them, but if you want to inspect first:
gcloud compute networks subnets list --filter="network:default"
Step 4: Delete the default network
gcloud compute networks delete default --quiet
Step 5: Create a custom mode replacement
Build a network with only the regions you use and firewall rules scoped to real sources.
# Custom mode network, no automatic subnets
gcloud compute networks create prod-vpc \
--subnet-mode=custom
# One subnet in the region you actually deploy to
gcloud compute networks subnets create prod-vpc-us-central1 \
--network=prod-vpc \
--region=us-central1 \
--range=10.10.0.0/20
# SSH only from your corporate or IAP range, not the internet
gcloud compute firewall-rules create allow-ssh-from-iap \
--network=prod-vpc \
--direction=INGRESS \
--action=ALLOW \
--rules=tcp:22 \
--source-ranges=35.235.240.0/20
Tip: The 35.235.240.0/20 range above is Google's Identity-Aware Proxy (IAP) range. Allowing SSH only from IAP and using gcloud compute ssh --tunnel-through-iap means you never expose port 22 to the public internet and you get IAM-based access control on top.
Doing it in Terraform
If you manage infrastructure as code, define the custom network explicitly and never reference the default one.
resource "google_compute_network" "prod_vpc" {
name = "prod-vpc"
auto_create_subnetworks = false
routing_mode = "REGIONAL"
}
resource "google_compute_subnetwork" "us_central1" {
name = "prod-vpc-us-central1"
network = google_compute_network.prod_vpc.id
region = "us-central1"
ip_cidr_range = "10.10.0.0/20"
}
resource "google_compute_firewall" "allow_ssh_iap" {
name = "allow-ssh-from-iap"
network = google_compute_network.prod_vpc.id
direction = "INGRESS"
allow {
protocol = "tcp"
ports = ["22"]
}
source_ranges = ["35.235.240.0/20"]
}
How to prevent it from happening again
Deleting the default network once is fine, but new projects will keep creating it unless you change how projects are provisioned.
Skip default network creation at the org level
The cleanest prevention is the compute.skipDefaultNetworkCreation organization policy constraint. Enforce it and no project under the org will ever get a default VPC again.
gcloud resource-manager org-policies enable-enforce \
compute.skipDefaultNetworkCreation \
--organization=YOUR_ORG_ID
Or in Terraform:
resource "google_organization_policy" "skip_default_network" {
org_id = var.org_id
constraint = "compute.skipDefaultNetworkCreation"
boolean_policy {
enforced = true
}
}
Note: This policy only affects projects created after it is enforced. Existing projects keep their default network, so you still need to clean those up manually or with a script that iterates over your projects.
Add a guardrail against public management ports
While you are setting org policies, enforce compute.vmExternalIpAccess to restrict which VMs can get external IPs, and consider a policy that blocks 0.0.0.0/0 ingress on sensitive ports. Policy-as-code tools like OPA Gatekeeper or Terraform validation can reject any firewall rule that opens 22 or 3389 to the internet before it ever applies.
Catch it in CI/CD
Run a scan on every plan or every merge. A simple gate with gcloud can fail the pipeline if a default network reappears:
if gcloud compute networks describe default \
--project="$PROJECT_ID" &>/dev/null; then
echo "ERROR: default VPC network exists in $PROJECT_ID"
exit 1
fi
Tip: Lensix runs the vpc_defaultnetwork check continuously across all your GCP projects, so you find out a default network reappeared without writing your own scan or remembering to run it. Pair it with the org policy above and you get prevention plus verification.
Best practices
- Always use custom mode networks. Auto mode creates subnets you did not ask for in regions you do not use. Custom mode means every subnet is a deliberate choice.
- Never allow management ports from
0.0.0.0/0. Use IAP for SSH and RDP, or a bastion host on a locked-down range. Public SSH is one of the most common entry points in cloud breaches. - Segment with firewall rules and tags. Replace the all-to-all
default-allow-internalrule with rules that only allow the traffic specific workloads need. Use network tags or service accounts as targets. - Plan your address space. Pick non-overlapping CIDR ranges per environment so you can peer or connect networks later without renumbering.
- Enforce policy at the org, not the project. Project-level cleanup does not scale. Org policies and a shared VPC pattern keep every project consistent by default.
- Review firewall rules on a schedule. Rules accumulate. A quarterly audit of who can reach what, sourced from your actual config, catches drift before it becomes an incident.
The default VPC is a starting point Google provides for convenience, not a network design. Treat it as scaffolding to be removed, replace it with something you actually designed, and put a policy in place so you never have to think about it on the next project.

