CloudQuery is joining env zero! We're moving from data to decisions.

Read the Announcement ❯

Read the Announcement ❯

AWS
Security
Tutorials

Finding AWS Unrestricted Outbound Access in 2026: EC2, Lambda, and Beyond

Joe Karlsson

Joe Karlsson

16 min read

The most-discussed part of Log4Shell (CVE-2021-44228) was the vulnerable library. The most fixable part was always condition three: unrestricted outbound access to download the malicious payload. Security teams spent weeks in December 2021 patching condition one. Blocking condition three takes a query and an afternoon - and it's the same condition that enables ransomware C2 callbacks, data exfiltration, and supply chain attacks today.
The compute surface has also grown significantly since 2021. Most teams now run workloads on Lambda, ECS Fargate, and EKS nodes alongside EC2, and each service can have unrestricted outbound access through misconfigured security groups. The queries below cover all of them.

Why Egress Controls Break the Attack Chain #

The Log4Shell kill chain is a clean illustration. Without outbound connectivity, an exploited process can't reach the attacker's LDAP server to download a malicious class file. The exploit fails at step three regardless of whether the software is patched. The same logic applies to ransomware: an infected workload needs to reach a command-and-control server to receive instructions and encryption keys. Block the outbound path and the attack stalls.
Vulert's 2025 analysis found that roughly 13% of Log4j downloads were still vulnerable versions - so Log4Shell isn't just historical. The Log4j family also didn't stop at one CVE: CVE-2021-45046 and CVE-2021-45105 arrived within days of the original disclosure. For teams that haven't fully remediated, egress controls remain an active mitigation, not just a retrospective exercise.
Several compliance frameworks have codified this as a mandatory control:
  • CIS AWS Foundations Benchmark v3.0.0 Control 5.4 (Level 1): The default security group of every VPC must restrict all traffic, both inbound and outbound. The default VPC security group ships with all outbound allowed.
  • NIST SP 800-53 Rev 5 SC-7(5): Deny by default, allow by exception for all network boundaries.
  • AWS FSBP EC2.2: VPC default security groups should not allow inbound or outbound traffic.
  • AWS FSBP EC2.19: Security groups should not allow unrestricted access to high-risk ports.
AWS Security Hub added support for CIS AWS Foundations Benchmark v3.0.0 in May 2024, so these controls now evaluate continuously across your entire AWS Organization without any manual query work.

How AWS Egress Controls Actually Work #

There are four distinct layers between a workload and the internet. Security groups are the most immediate, but you need all of them in context to understand what "exposed" actually means:
LayerControlWhere It AppliesDefault State
1Security groupsAttached to each ENI/resourceAll outbound allowed
2VPC routing + Internet GatewaySubnet route tablesNo IGW in new VPCs
3NACLsSubnet level, statelessAll traffic allowed
4DNS Firewall / Network FirewallVPC or Transit GatewayNot enabled by default
This post focuses on layers 1 and 2. NACLs are stateless and harder to reason about accurately, and in practice, most teams configure egress at the security group layer rather than the NACL layer.

Building the Egress Rules View #

Before querying specific compute types, create a reusable view that extracts egress rules from aws_ec2_security_groups. The ip_permissions_egress column is a JSONB array that requires some unpacking. For full documentation on the security groups table schema, see the AWS EC2 Security Groups table reference - our deep-dive on this table covers every column in detail.
Prerequisite: Run cloudquery sync to populate your database with the AWS Source integration. If you're running multiple AWS accounts, the AWS Source supports AWS Organizations - one configuration syncs all accounts so these queries return results across your entire estate, not just one account at a time.
CREATE OR REPLACE VIEW view_aws_sg_egress_rules AS
SELECT
    account_id,
    region,
    group_name,
    group_id AS id,
    vpc_id,
    (i->>'FromPort')::integer AS from_port,
    (i->>'ToPort')::integer AS to_port,
    i->>'IpProtocol' AS ip_protocol,
    ip_ranges->>'CidrIp' AS ip,
    ip6_ranges->>'CidrIpv6' AS ip6
FROM aws_ec2_security_groups,
    JSONB_ARRAY_ELEMENTS(ip_permissions_egress) AS i
LEFT JOIN LATERAL JSONB_ARRAY_ELEMENTS(i->'IpRanges') AS ip_ranges ON true
LEFT JOIN LATERAL JSONB_ARRAY_ELEMENTS(i->'Ipv6Ranges') AS ip6_ranges ON true;
Two CIDR patterns indicate unrestricted egress: ip = '0.0.0.0/0' (all IPv4) and ip6 = '::/0' (all IPv6). Worth calling out separately: ip_protocol = '-1' means all protocols and all ports. A security group with -1 egress to 0.0.0.0/0 is completely unrestricted outbound - a different risk level than a single port being open.
You can also audit security groups independently before worrying about which resources are attached. This catches misconfigured groups before they get reused on a new instance:
-- Security groups with unrestricted egress (all destinations)
SELECT DISTINCT
    account_id,
    region,
    group_name,
    id AS group_id,
    ip_protocol,
    from_port,
    to_port
FROM view_aws_sg_egress_rules
WHERE ip = '0.0.0.0/0' OR ip6 = '::/0';
A narrower cut worth running separately: security groups where ip_protocol = '-1' allows all protocols and all ports. These are the highest-risk rules - broader than a single port being open, and worth prioritizing in triage:
-- Highest-risk: security groups with all-protocol egress to 0.0.0.0/0
SELECT DISTINCT
    account_id,
    region,
    group_name,
    id AS group_id
FROM view_aws_sg_egress_rules
WHERE ip_protocol = '-1'
  AND (ip = '0.0.0.0/0' OR ip6 = '::/0');
CIS AWS Foundations Benchmark v3.0.0 Control 5.4 specifically targets default VPC security groups - they must have zero inbound and outbound rules. The default security group ships with all outbound allowed, so this is a common finding. This query surfaces it directly:
-- CIS Control 5.4: default security groups should have no inbound or outbound rules
SELECT
    account_id,
    region,
    group_id,
    CASE
        WHEN group_name = 'default'
          AND (jsonb_array_length(ip_permissions) > 0
            OR jsonb_array_length(ip_permissions_egress) > 0)
        THEN 'fail'
        ELSE 'pass'
    END AS cis_5_4_status
FROM aws_ec2_security_groups
WHERE group_name = 'default';

Which EC2 Instances Are Actually Exposed? #

An open egress security group doesn't automatically mean internet access. The instance also needs to be in a VPC with an internet gateway attached. This query joins aws_ec2_instances with your egress view and filters for VPCs with an attached gateway:
-- EC2 instances with unrestricted egress AND an internet gateway in their VPC
SELECT
    i.account_id,
    i.region,
    i.instance_id,
    sg->>'GroupId' AS security_group_id,
    sg->>'GroupName' AS security_group_name
FROM aws_ec2_instances i,
    JSONB_ARRAY_ELEMENTS(i.security_groups) AS sg
INNER JOIN view_aws_sg_egress_rules egress ON egress.id = sg->>'GroupId'
WHERE
    (egress.ip = '0.0.0.0/0' OR egress.ip6 = '::/0')
    AND (
        i.vpc_id IN (
            SELECT value->>'VpcId'
            FROM aws_ec2_internet_gateways,
            JSONB_ARRAY_ELEMENTS(attachments) AS value
        )
        OR i.vpc_id IN (
            SELECT value->>'VpcId'
            FROM aws_ec2_egress_only_internet_gateways,
            JSONB_ARRAY_ELEMENTS(attachments) AS value
        )
    );
Depending on your account history, the results are probably larger than you expect. Dev environments and legacy accounts are full of security groups that were created for a quick test in 2019 and never tightened up. It's common to find dozens of instances with open egress in development VPCs that have been running for years - technically exposed, but not processing anything sensitive. Knowing the difference between "open" and "open and hosting production data" is what makes the triage tractable.
The practical first move is tagging rather than immediately closing rules. Add egress-justified=true and egress-reason=<description> tags to instances where the access is intentional and documented. Re-run the query and filter out tagged instances to focus on what still needs review. It's a slower approach than bulk-fixing, but it avoids breaking things you don't understand yet.

Lambda Functions in VPC with Open Egress #

Lambda outside a VPC has internet access by default through AWS-managed infrastructure - that's by design, and there's no security group controlling it. Once you put Lambda inside a VPC, it behaves like an EC2 instance: it needs a permissive security group and a route to an internet gateway or NAT Gateway to reach the internet.
The VPC configuration lives inside the configuration JSON column on aws_lambda_functions:
-- Lambda functions deployed inside a VPC with unrestricted egress security groups
SELECT
    f.account_id,
    f.region,
    f.arn,
    sg_id AS security_group_id
FROM aws_lambda_functions f,
    JSONB_ARRAY_ELEMENTS_TEXT(
        f.configuration->'VpcConfig'->'SecurityGroupIds'
    ) AS sg_id
INNER JOIN view_aws_sg_egress_rules egress ON egress.id = sg_id
WHERE
    f.configuration->'VpcConfig'->>'VpcId' IS NOT NULL
    AND f.configuration->'VpcConfig'->>'VpcId' != ''
    AND (egress.ip = '0.0.0.0/0' OR egress.ip6 = '::/0');
The VpcConfig->>'VpcId' IS NOT NULL filter keeps this to Lambda functions actually inside a VPC. Functions without VPC config have a null or empty VpcId - they have internet access by design, and the mitigation there is IAM permissions (restricting what AWS APIs the function can call) rather than network-level egress control.

ECS and Fargate Tasks #

ECS Fargate tasks using awsvpc network mode - the only option for Fargate and the recommended mode for ECS on EC2 - get their own elastic network interface per task. That means each task has its own security group assignment, separate from the cluster. You can't audit the cluster's security groups and assume tasks are covered.
In awsvpc mode, each task's ENI shows up in aws_ec2_network_interfaces. ECS attaches these ENIs with descriptions matching the ECS task ARN pattern, and their security groups follow the same structure as EC2 instances:
-- ECS Fargate tasks (awsvpc mode) with unrestricted egress
SELECT
    eni.account_id,
    eni.region,
    eni.network_interface_id,
    eni.description,
    sg->>'GroupId' AS security_group_id
FROM aws_ec2_network_interfaces eni,
    JSONB_ARRAY_ELEMENTS(eni.groups) AS sg
INNER JOIN view_aws_sg_egress_rules egress ON egress.id = sg->>'GroupId'
WHERE
    eni.description LIKE 'arn:aws:ecs:%'
    AND (egress.ip = '0.0.0.0/0' OR egress.ip6 = '::/0');
If you're not seeing results you expect, run SELECT DISTINCT description FROM aws_ec2_network_interfaces LIMIT 50 to check what patterns your data actually uses - the format varies slightly by cluster name and launch type.
For EKS, node security groups control pod-level egress at the host layer. AWS launched enhanced network security policies for EKS in December 2025, adding DNS-based FQDN egress filtering at the pod level for Kubernetes 1.29+ clusters. Worth enabling if you want granular control beyond what node security groups provide.

What to Do When You Find Them #

Finding results is expected, especially in accounts that have been running for years. A few approaches that actually work:
Tag first, tighten later. Not every open egress rule is a problem, but untracked open egress rules are. Use egress-justified=true plus an egress-reason tag to acknowledge known-acceptable cases. It's not a security control on its own, but it gives you a working inventory of what's intentional vs. what's just forgotten from 2019. Once tagged, re-run the EC2 query with a NOT filter to focus only on what hasn't been reviewed yet:
-- EC2 instances with unrestricted egress, excluding tagged-justified instances
SELECT
    i.account_id,
    i.region,
    i.instance_id,
    sg->>'GroupId' AS security_group_id
FROM aws_ec2_instances i,
    JSONB_ARRAY_ELEMENTS(i.security_groups) AS sg
INNER JOIN view_aws_sg_egress_rules egress ON egress.id = sg->>'GroupId'
WHERE
    (egress.ip = '0.0.0.0/0' OR egress.ip6 = '::/0')
    AND i.vpc_id IN (
        SELECT value->>'VpcId' FROM aws_ec2_internet_gateways,
        JSONB_ARRAY_ELEMENTS(attachments) AS value
    )
    AND NOT (i.tags->>'egress-justified' = 'true');
At scale, manually reviewing and tagging across 20+ accounts stops being practical. CloudQuery Alerts can trigger automatically when this query returns new results - posting to Slack, opening a Jira ticket, or calling the AWS API to apply the egress-justified tag directly. The tagging workflow becomes a runbook, not a recurring manual task.
VPC Endpoints as the architectural fix. A large share of internet-bound traffic from AWS workloads goes to AWS services: S3, SSM, Secrets Manager, ECR, DynamoDB. You can route all of that traffic privately using VPC Interface and Gateway Endpoints. This eliminates the need for internet gateway routing for that entire class of traffic - a more sustainable fix than restricting egress rules service-by-service. It's also free for gateway endpoints (S3 and DynamoDB) and relatively cheap for interface endpoints.
NAT Gateway for workloads that need real outbound access. VPC Endpoints cover AWS service traffic, but some workloads genuinely need to reach third-party APIs or the broader internet. The right pattern for those is private subnet + NAT Gateway: the workload sits in a private subnet with no direct route to an internet gateway, and routes outbound traffic through a NAT Gateway in a public subnet. The result is outbound internet access without a public IP address, and no inbound connections from the internet are possible. You can still restrict egress to specific ports or CIDRs on the security group - NAT Gateway provides the routing path but doesn't change what the security group permits.
Continuous detection with AWS-native tools. AWS Security Hub's FSBP EC2.2 and EC2.19 controls run continuously across all accounts in your AWS Organization without any manual query work. The vpc-sg-open-only-to-authorized-ports Config rule flags security groups with unrestricted access on specific ports; restricted-common-ports covers commonly targeted ingress ports.
CloudQuery Policies for cross-account egress monitoring. If you're using CloudQuery Platform, you can codify the queries above as Policies that run continuously against your synced data. The advantage over one-off SQL runs: Policies fire against all accounts and regions, results land in your existing database (PostgreSQL, Snowflake, BigQuery, or whatever you're already using), and you can build remediation workflows on top of the findings. A security group that opened up after a deployment shows up in the next sync. Pair it with CloudQuery Alerts and you get notified in Slack or PagerDuty the moment a new ungrouped finding appears - no manual re-runs required.
Route 53 DNS Firewall for Layer 7 control. If your workloads need some internet access, Route 53 Resolver DNS Firewall lets you block outbound DNS queries to unauthorized domains. This is the AWS Security Maturity Model's Level 3 recommendation for outbound traffic control. It's the most practical first step toward blocking C2 callback patterns - most malware relies on DNS to reach command-and-control infrastructure, and DNS Firewall catches it at that layer without requiring full egress lockdown.
For a broader look at finding publicly accessible resources across AWS, see our post on detecting public databases across AWS, Azure, and GCP - the same pattern of "find the open resource, check if it's really exposed, triage by context" applies.

Key Takeaways #

  • Blocking egress breaks the attack chain for Log4Shell, ransomware C2, and data exfiltration - even when the underlying software is vulnerable
  • Real exposure requires two conditions: an open egress security group AND a VPC with an internet gateway attached
  • EC2 instances, Lambda-in-VPC, and ECS Fargate tasks in awsvpc mode all have security group-based egress worth auditing - check all three
  • CIS AWS Foundations Benchmark v3.0.0 Control 5.4 mandates default VPC security group restriction; AWS Security Hub has evaluated this continuously since May 2024
  • VPC Endpoints eliminate internet routing for AWS service traffic entirely - a better long-term fix than case-by-case security group restriction
Continuously Monitor Your AWS Egress Configuration
CloudQuery syncs your AWS security groups, VPC configuration, and compute inventory into SQL so these queries run against current data across every account and region. You own the data in your own database. See the documentation to get started.
See How CloudQuery Works

Frequently Asked Questions #

What Is Unrestricted Outbound Access in AWS? #

Unrestricted outbound access means a workload can initiate connections to any IP address on the internet, with no restrictions on destination, port, or protocol. In AWS, this is a security group egress rule allowing 0.0.0.0/0 (all IPv4) or ::/0 (all IPv6). Real exposure requires both an open egress rule AND a VPC with an internet gateway - an open security group in a subnet with no internet gateway is much lower risk.

Does Log4Shell Still Matter in 2026? #

Yes, for two reasons. First, roughly 13% of Log4j downloads are still vulnerable versions as of 2025. Second, Log4Shell is the clearest real-world example of why egress controls are a security control and not just network hygiene. The three-condition model applies to any vulnerability that requires an outbound callback: supply chain implants, web shell C2 communication, and data exfiltration channels all share the same dependency on unrestricted outbound access.

What Is the Difference Between Security Groups and NACLs for Egress Control? #

Security groups are stateful and attached directly to a network interface - if you allow inbound traffic on port 443, return traffic is automatically allowed. NACLs are stateless and applied at the subnet level, requiring explicit rules for both directions including return traffic. Security groups are the practical primary control for egress management because they operate at the resource level and are easier to reason about. NACLs are useful for defense in depth but easier to misconfigure due to stateless return traffic rules.

What AWS Config Rules Detect Unrestricted Outbound Access? #

The two most relevant managed rules are vpc-sg-open-only-to-authorized-ports, which flags security groups allowing unrestricted access on ports outside a configured authorized list, and restricted-common-ports, which covers unrestricted TCP ingress on commonly targeted ports. AWS Security Hub's FSBP EC2.2 and EC2.19 controls evaluate the same conditions and aggregate findings across all accounts in your AWS Organization.

Does Lambda Need a VPC to Be Protected by Egress Controls? #

Lambda outside a VPC has internet access by default - there's no security group to audit. Once deployed inside a VPC, Lambda uses the same security group and routing rules as EC2. For Lambda outside a VPC, the mitigation is IAM (restricting which AWS APIs the function can call) rather than network-level egress control. Most Lambda functions don't need a VPC - adding one introduces cold start latency and complexity unless you specifically need access to private VPC resources.

What CIS Benchmark Control Covers AWS Egress Restrictions? #

CIS AWS Foundations Benchmark v3.0.0 Control 5.4 (Level 1) requires that the default security group of every VPC restricts all traffic, both inbound and outbound. The default VPC security group ships with all outbound allowed, so this control requires an explicit change. AWS Security Hub has evaluated against CIS v3.0.0 since May 2024.

How Do I Fix Unrestricted Outbound Access Without Breaking Workloads? #

Start by running the queries above and tagging results as justified or unjustified. Then deploy VPC Endpoints for AWS services (S3, SSM, ECR, Secrets Manager, DynamoDB) - this removes the need for internet routing on the most common traffic patterns without changing any security group rules. For remaining workloads, enable VPC Flow Logs and analyze actual outbound destinations over a week or two, then build specific egress rules based on observed traffic. Much lower risk than bulk-restricting all open security groups at once.
Turn cloud chaos into clarity

Find out how CloudQuery can help you get clarity from a chaotic cloud environment with a personalized conversation and demo.