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:
- An active VPC peering connection (either as requester or accepter)
- A Transit Gateway attachment in an
availablestate - An internet gateway attached to it
- A VPN gateway with an active connection
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.
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.
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:
- Empty VPC (no resources): Delete it. An empty VPC costs nothing but adds noise to your inventory and any topology audits.
- VPC with stopped instances only: Evaluate whether those instances have any data that needs preserving. Snapshot EBS volumes if needed, then terminate instances and delete the VPC.
- VPC with running instances: Determine ownership. Tag the VPC and its resources with a team/project tag if missing. If the workload is still needed, integrate the VPC into your network (add a TGW attachment or peering connection and update routing). If it's not needed, follow a decommission process: terminate instances, delete associated resources in order, then delete the VPC.
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.