Most AWS accounts accumulate VPCs over time. Some are well-maintained and connected to the rest of the network. Others are forgotten — created for a project that ended, left over from a migration that never finished, or abandoned when an engineer left the team. These are orphaned VPCs, and they represent a category of risk that most organizations don't actively monitor for.

This post explains exactly what makes a VPC "orphaned," why they tend to appear, why they matter for security and cost, and how to systematically find them in your AWS account.

What Is an Orphaned VPC?

An orphaned VPC is a VPC that has no active connections to the rest of your network. Specifically, it has none of the following:

A VPC in this state is completely isolated. Resources inside it can't reach other VPCs, can't reach the internet, and nothing outside can reach in. From a network topology perspective, it's a dead end — a segment that exists on paper but is unreachable from anywhere else in your account or the public internet.

Note on the default VPC: Every AWS region includes a default VPC with a default internet gateway attached. The default VPC is never orphaned by this definition, even if you never use it. The risk of orphaned VPCs applies to non-default VPCs you've created intentionally.

Why Do Orphaned VPCs Happen?

Orphaned VPCs are almost never created intentionally. They accumulate over time from predictable situations:

Old Environments Left Running

A developer spins up a VPC for a staging or load-test environment. The project ships, the environment is no longer needed, but the VPC isn't deleted — just disconnected. The peering connection to the production VPC is removed, but the VPC itself (and possibly the EC2 instances and RDS databases inside it) keeps running.

Team Offboarding

An engineer leaves the team. They were maintaining a set of experimental or development VPCs under a project that didn't survive them. No one else knows the VPC exists, and it never makes it into a decommission ticket.

Account Consolidations

Organizations moving workloads between AWS accounts sometimes migrate the resources but not the network plumbing. A VPC in the old account ends up with its peering connections removed as part of account cleanup, but the VPC itself is left behind along with anything still running inside.

Failed Migrations

A migration effort creates a new VPC for the destination environment, begins moving workloads, then stalls or gets cancelled. The new VPC has a few partially-migrated resources, no valid connections back to the source environment, and no one with context on what it contains.

Sandbox VPCs

Sandbox or experiment VPCs created for testing are intentionally isolated during creation, then simply forgotten. They may have been connected to a TGW temporarily, had the attachment deleted, and are now islands.

Why Orphaned VPCs Matter

Security Risk

An orphaned VPC is unmonitored network space. Resources inside it may not be receiving OS or application security patches — since they can't reach a package repository or Systems Manager endpoint. They may not be covered by your security scanning tools. If the VPC was created with permissive security groups ("allow all from 0.0.0.0/0") and was later disconnected from the internet gateway, those misconfigured rules sit dormant until the VPC is reconnected — at which point everything is immediately exposed.

For compliance frameworks like PCI DSS, SOC 2, or HIPAA, an orphaned VPC represents a segment of your infrastructure that your controls don't cover and your auditors can't see. That's a finding.

Cost

Resources inside orphaned VPCs continue to accrue charges. EC2 instances, RDS databases, NAT gateways, and load balancers all run whether or not traffic is flowing through them. Orphaned VPCs also often contain Elastic IPs that aren't attached to running instances — AWS charges $0.005/hr for unattached EIPs, which adds up across a fleet of forgotten VPCs.

Compliance

Most compliance audits require a complete inventory of compute and network resources. An orphaned VPC with running instances that isn't in your asset inventory is a gap. Auditors will find it by pulling describe-vpcs and cross-referencing it with your documented network topology. Better to find it yourself first.

How to Find Orphaned VPCs with the AWS CLI

Finding orphaned VPCs requires cross-referencing several API calls. The approach is: get all VPC IDs, then filter out any that appear in peering connections, TGW attachments, or internet gateway associations.

Step 1: List All VPCs

aws ec2 describe-vpcs \
  --query 'Vpcs[*].{VpcId:VpcId,CIDR:CidrBlock,Name:Tags[?Key==`Name`].Value|[0],IsDefault:IsDefault}' \
  --output table

Step 2: List VPCs with Active Peering Connections

aws ec2 describe-vpc-peering-connections \
  --filters "Name=status-code,Values=active,provisioning" \
  --query 'VpcPeeringConnections[*].[RequesterVpcInfo.VpcId,AccepterVpcInfo.VpcId]' \
  --output text

Step 3: List VPCs with TGW Attachments

aws ec2 describe-transit-gateway-attachments \
  --filters "Name=resource-type,Values=vpc" "Name=state,Values=available,pending" \
  --query 'TransitGatewayAttachments[*].ResourceId' \
  --output text

Step 4: List VPCs with an Attached Internet Gateway

aws ec2 describe-internet-gateways \
  --filters "Name=attachment.state,Values=available" \
  --query 'InternetGateways[*].Attachments[*].VpcId' \
  --output text

Any VPC ID from Step 1 that does not appear in the output of Steps 2, 3, or 4 is an orphaned VPC. You can automate this cross-reference in a shell script or pipe the outputs into a tool like comm or jq for programmatic comparison.

Multi-region note: VPCs are region-scoped. Run each of these commands in every region where you have VPCs. Use aws ec2 describe-regions --query 'Regions[*].RegionName' --output text to get the full list of enabled regions in your account.

Step 5: Check What's Running Inside

Once you've identified orphaned VPCs, find out what's still running inside them before you take action:

# Running instances in a VPC
aws ec2 describe-instances \
  --filters "Name=vpc-id,Values=vpc-0abc12345" "Name=instance-state-name,Values=running,stopped" \
  --query 'Reservations[*].Instances[*].{ID:InstanceId,Type:InstanceType,State:State.Name,Name:Tags[?Key==`Name`].Value|[0]}' \
  --output table

# RDS instances in a VPC
aws rds describe-db-instances \
  --query "DBInstances[?DBSubnetGroup.VpcId=='vpc-0abc12345'].{ID:DBInstanceIdentifier,Class:DBInstanceClass,Engine:Engine,Status:DBInstanceStatus}" \
  --output table

# Unattached Elastic IPs (account-wide, filter by VPC if needed)
aws ec2 describe-addresses \
  --query 'Addresses[?AssociationId==null].{AllocationId:AllocationId,IP:PublicIp}' \
  --output table

What to Do When You Find One

When you identify an orphaned VPC, the decision tree is straightforward:

Trying to delete a VPC with active resources will fail — AWS will return an error listing the dependency. The correct teardown order is: terminate EC2 instances, delete NAT gateways, release Elastic IPs, delete load balancers, delete RDS instances (or take final snapshots), delete subnets, delete non-default security groups, delete non-main route tables, detach and delete any remaining gateways, then delete the VPC.

Making Orphan Detection Continuous

Running these CLI commands manually once is useful. Running them on a schedule — or better yet, having a tool that surfaces orphaned VPCs as a finding every time it scans — is what gives you ongoing visibility. Without continuous detection, orphaned VPCs accumulate between audits, and the gap between when one appears and when you discover it can stretch to months.