Back to Checks
aws

Security group has no ingress or egress rules with public IPv4 CIDR ranges from /1 to /23

ec2_securitygroup_allow_wide_open_public_ipv4
Service: ec2Severity: high
OfficialBuilt-inVerified
Categories:internet-exposed
Resource Type:AwsEc2SecurityGroup

EC2 security groups with rules that permit non-RFC1918 IPv4 ranges wider than /24 are identified across both ingress and egress.

The focus is on public CIDRs (/1-/23) that broadly expose sources or destinations, not on private networks.

Risk

Over-broad public CIDRs expand exposure and enable:

  • Confidentiality loss via unauthorized access and exfiltration
  • Integrity compromise by exploiting exposed services
  • Availability impact from scanning and abuse

Open egress further allows C2 beacons and bulk data exfiltration to untrusted IPs.

Run this check with Prowler

Run in Prowler Cloud
Run
prowler aws --checks ec2_securitygroup_allow_wide_open_public_ipv4

Recommendation

Apply least privilege on security groups:

  • Allow only known IPs (prefer /32 or tight CIDRs)
  • Use private connectivity (VPN, Direct Connect, private endpoints)
  • Restrict and log egress; deny by default
  • Segment with security group references and network ACLs for defense-in-depth

Remediation

Terraform

# Terraform: ensure no public IPv4 CIDR wider than /24
resource "aws_security_group" "<example_resource_name>" {
  name   = "<example_resource_name>"
  vpc_id = "<example_resource_id>"

  ingress {
    from_port   = 443
    to_port     = 443
    protocol    = "tcp"
    cidr_blocks = ["203.0.113.0/24"] # Critical: /24 (or private RFC1918) avoids wide-open public /1-/23
  }
}

NativeIaC

# CloudFormation: ensure no public IPv4 CIDR wider than /24
Resources:
  "<example_resource_name>":
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: "sg"
      VpcId: "<example_resource_id>"
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 443
          ToPort: 443
          CidrIp: 203.0.113.0/24  # Critical: /24 (or private RFC1918) avoids wide-open public /1-/23

Other

1In the AWS Console, go to VPC > Security Groups
2Select the security group with the finding
3Click Edit inbound rules (and Edit outbound rules if needed)
4For any rule with a public IPv4 CIDR mask /1-/23, delete it or change the CIDR to a private RFC1918 range or to /24 or more specific (e.g., 203.0.113.0/24)
5Save rules

Check Code

import ipaddress

from prowler.lib.check.models import Check, Check_Report_AWS
from prowler.providers.aws.services.ec2.ec2_client import ec2_client
from prowler.providers.aws.services.vpc.vpc_client import vpc_client


class ec2_securitygroup_allow_wide_open_public_ipv4(Check):
    def execute(self):
        findings = []
        cidr_treshold = 24
        for security_group_arn, security_group in ec2_client.security_groups.items():
            # Check if ignoring flag is set and if the VPC and the SG is in use
            if ec2_client.provider.scan_unused_services or (
                security_group.vpc_id in vpc_client.vpcs
                and vpc_client.vpcs[security_group.vpc_id].in_use
                and len(security_group.network_interfaces) > 0
            ):
                report = Check_Report_AWS(
                    metadata=self.metadata(), resource=security_group
                )
                report.resource_details = security_group.name
                report.status = "PASS"
                report.status_extended = f"Security group {security_group.name} ({security_group.id}) has no potential wide-open non-RFC1918 address."
                # Loop through every security group's ingress rule and check it
                for ingress_rule in security_group.ingress_rules:
                    for ipv4 in ingress_rule["IpRanges"]:
                        ip = ipaddress.ip_network(ipv4["CidrIp"])
                        # Check if IP is public if 0 < prefixlen < 24
                        if (
                            ip.is_global
                            and ip.prefixlen < cidr_treshold
                            and ip.prefixlen > 0
                        ):
                            report.status = "FAIL"
                            report.status_extended = f"Security group {security_group.name} ({security_group.id}) has potential wide-open non-RFC1918 address {ipv4['CidrIp']} in ingress rule."
                            break

                # Loop through every security group's egress rule and check it
                for egress_rule in security_group.egress_rules:
                    for ipv4 in egress_rule["IpRanges"]:
                        ip = ipaddress.ip_network(ipv4["CidrIp"])
                        # Check if IP is public if 0 < prefixlen < 24
                        if (
                            ip.is_global
                            and ip.prefixlen < cidr_treshold
                            and ip.prefixlen > 0
                        ):
                            report.status = "FAIL"
                            report.status_extended = f"Security group {security_group.name} ({security_group.id}) has potential wide-open non-RFC1918 address {ipv4['CidrIp']} in egress rule."
                            break

                findings.append(report)

        return findings