This check flags Compute Engine VMs with IP forwarding enabled, which lets an instance send and receive packets with source or destination IPs that do not match its own. Unless the VM is a deliberate router, NAT gateway, or appliance, turn it off, and since the setting is immutable on a running instance, you fix it by recreating the VM with --no-can-ip-forward.
By default, Google Cloud drops any packet leaving a VM whose source IP does not belong to that VM, and any packet arriving whose destination IP is not the VM. This anti-spoofing behavior is a quiet but important guardrail. When you enable IP forwarding, you switch it off and the VM becomes capable of acting as a router, forwarding traffic on behalf of other addresses.
That is exactly what you want for a NAT instance, a software VPN, or a network virtual appliance. It is exactly what you do not want on a general-purpose application server, and an attacker who lands on such a host will happily use it to pivot.
What this check detects
The compute_ipforwarding check inspects every Compute Engine instance in your GCP projects and looks at the canIpForward property. When it is set to true, the check flags the VM.
In the API and in Terraform this maps to a single boolean. In gcloud it shows up like this:
gcloud compute instances describe my-vm \
--zone=us-central1-a \
--format="value(canIpForward)"
# true
Note: IP forwarding is an instance-level property in GCP. It is not a firewall rule or a route, so you cannot scope it down with target tags. It is either on or off for the entire VM, across every network interface attached to it.
The check does not assume every flagged VM is a problem. Routers and appliances legitimately need this. The point is to surface every instance with the setting on so you can confirm each one has a reason to be there.
Why it matters
The source/destination check that GCP performs by default is anti-spoofing protection. With IP forwarding enabled, a compromised VM gains three capabilities it should not have on a normal workload.
1. Network pivoting and lateral movement
If an attacker gets a foothold on a VM with IP forwarding on, that host can forward packets toward other internal addresses and rewrite source IPs to evade origin-based controls. It becomes a relay deeper into your VPC. A web server that should only ever talk to its database now behaves like a transit node, and your network segmentation assumptions stop holding.
2. Spoofing and detection evasion
Normally a VM cannot send a packet claiming to be from another IP, because GCP drops it. With forwarding on, it can. That makes traffic harder to attribute, undermines flow-log based detection, and lets an attacker impersonate trusted internal services.
3. Man-in-the-middle positioning
A forwarding-capable host on a shared subnet can be combined with route manipulation or compromised routing config to sit in the path of traffic between other workloads. Combined with a custom route that points at the VM, it can intercept or inspect traffic that was never meant for it.
Warning: IP forwarding by itself does not route traffic to a VM. It needs a matching VPC route or NAT setup to actually receive third-party traffic. But leaving the capability on means a single additional misconfiguration, or a single compromised instance, turns a theoretical risk into a working pivot. Treat it as removing a safety latch.
From a compliance angle, frameworks like CIS GCP Benchmark call out IP forwarding explicitly because it weakens the network isolation that auditors expect to see between tiers.
How to fix it
Here is the catch that surprises most people: you cannot toggle canIpForward on an existing instance. It can only be set at creation time. To disable it on a running VM, you have to recreate the instance.
The recommended path is to create a machine image or snapshot, delete the VM, and recreate it with forwarding off.
Danger: Deleting and recreating a VM is disruptive and, depending on your disk configuration, can be irreversible. Confirm you have a snapshot or image, and that any non-boot data disks are set to persist, before you delete anything. Do this in a maintenance window for production.
Step 1: Snapshot the disks
gcloud compute disks snapshot my-vm-boot-disk \
--zone=us-central1-a \
--snapshot-names=my-vm-boot-disk-pre-fix
Step 2: Capture the existing config
Grab the machine type, network, tags, and service account so the rebuilt VM matches.
gcloud compute instances describe my-vm \
--zone=us-central1-a \
--format=yaml > my-vm-config.yaml
Step 3: Delete the instance, keep the data disks
gcloud compute instances delete my-vm \
--zone=us-central1-a \
--keep-disks=data
Step 4: Recreate with forwarding disabled
gcloud compute instances create my-vm \
--zone=us-central1-a \
--machine-type=e2-standard-2 \
--network=my-vpc \
--subnet=my-subnet \
--no-can-ip-forward \
--disk=name=my-vm-boot-disk,boot=yes
The --no-can-ip-forward flag is the explicit form. If you omit any IP-forwarding flag entirely, instances default to off, which is what you want.
Fixing it in Terraform
If the VM is managed by Terraform, set can_ip_forward to false (or remove it, since false is the default). Terraform will plan a replacement because the attribute forces a new resource.
resource "google_compute_instance" "app" {
name = "my-vm"
machine_type = "e2-standard-2"
zone = "us-central1-a"
can_ip_forward = false # explicit and safe
boot_disk {
initialize_params {
image = "debian-cloud/debian-12"
}
}
network_interface {
subnetwork = google_compute_subnetwork.my_subnet.id
}
}
Tip: Before applying, run terraform plan and confirm the change shows as a replacement, not an in-place update. If it shows in-place, your state is drifted and the apply will fail. Refresh state first.
What if the VM genuinely needs IP forwarding?
If the instance really is a NAT gateway, VPN server, or network appliance, then this is a true positive that you accept rather than fix. Document the exception, tag the VM clearly (for example role=nat-gateway), and suppress the finding in Lensix so it does not keep alerting. The goal is an empty list of unexplained forwarding VMs, not zero forwarding VMs everywhere.
How to prevent it from happening again
Because the setting is immutable, catching it before deployment is far cheaper than remediating later. Push the control left.
Organization Policy constraint
GCP has a built-in org policy that restricts IP forwarding across projects. Apply it at the org or folder level and allow-list only the appliances that need it.
gcloud resource-manager org-policies set-policy policy.yaml
Where policy.yaml denies forwarding by default:
constraint: constraints/compute.vmCanIpForward
listPolicy:
deniedValues:
- is:all
# add allowedValues for specific instances that must forward
Note: The compute.vmCanIpForward constraint takes instance identifiers in the form projects/PROJECT/zones/ZONE/instances/NAME for its allow-list. Plan your appliance naming so exceptions are easy to express.
Policy-as-code in CI/CD
For Terraform-managed infrastructure, block the merge before the plan ever reaches GCP. A simple Conftest/OPA rule catches it:
package main
deny[msg] {
resource := input.resource.google_compute_instance[name]
resource.can_ip_forward == true
not allowed_forwarders[name]
msg := sprintf("Instance '%s' has IP forwarding enabled; add to allowlist if intentional", [name])
}
allowed_forwarders := {"nat-gateway", "vpn-appliance"}
Wire this into the pull request pipeline so a plan that introduces an unapproved forwarding VM fails the check and never gets applied.
Tip: Pair the org policy with the CI gate. The org policy is your last-resort enforcement that catches console clicks and out-of-band scripts, while the CI gate gives developers fast feedback with a clear message before anything is provisioned.
Best practices
- Default to off. Treat IP forwarding as an explicit, justified exception rather than something you leave at whatever a template happened to set.
- Use managed services for routing. For outbound internet from private VMs, use Cloud NAT instead of a self-managed NAT instance. It removes the need for a forwarding VM entirely and scales without a single point of failure.
- Isolate appliances. When you do run a forwarding VM, put it in its own subnet, restrict its firewall rules tightly, and give it a minimal service account. A router with broad IAM is a much bigger prize.
- Tag and document exceptions. Every forwarding VM should be self-explanatory from its labels. If you cannot tell why a VM forwards traffic by looking at it, neither can your incident responder at 3am.
- Scan continuously. Because the setting can only be fixed by recreation, the value of catching it early compounds. Continuous monitoring means you catch a new forwarding VM the day it appears, not six months into an audit.
The cheapest place to fix an immutable setting is before the resource exists. Everything after that is a rebuild.
IP forwarding is a small flag with outsized consequences. On the right appliance it is essential infrastructure. On a random application server it is a pre-built pivot point waiting for an attacker. Review every flagged VM, fix the ones that have no reason to forward, and put a policy gate in front of new ones so the list stays short.

