Back to Checks
aws

Security group has no 0.0.0.0/0 or ::/0 ingress to any port, or is attached only to allowed interface types or instance owners

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

EC2 security groups with internet-sourced ingress from 0.0.0.0/0 or ::/0 to any port, and their attachments, are evaluated. Groups linked to network interfaces or instance owners outside an approved list for public exposure are identified.

Risk

Open ingress to any port on non-approved interfaces enables external scanning, brute force, and exploitation of unintended services. This threatens confidentiality (unauthorized access), integrity (tampering), and availability (DoS), and facilitates lateral movement.

Run this check with Prowler

Run in Prowler Cloud
Run
prowler aws --checks ec2_securitygroup_allow_ingress_from_internet_to_any_port

Recommendation

Apply least privilege: restrict ingress to required ports and trusted sources; avoid 0.0.0.0/0 and ::/0 except for managed public endpoints. Place workloads behind load balancers, API gateways, or WAFs; use private networking. Allow public rules only on approved interface types.

Remediation

Terraform

# Security group with no Internet-open ingress
resource "aws_security_group" "<example_resource_name>" {
  name   = "<example_resource_name>"
  vpc_id = "<example_resource_id>"
  # Critical: no ingress blocks -> prevents 0.0.0.0/0 or ::/0 inbound
}

NativeIaC

# CloudFormation: security group without Internet-open ingress
Resources:
  <example_resource_name>:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: "SG without Internet ingress"
      VpcId: "<example_resource_id>"
      SecurityGroupIngress: []  # Critical: no 0.0.0.0/0 or ::/0 inbound; denies all inbound

Other

1In the AWS console, go to EC2 > Security Groups
2Select the affected security group
3Open Inbound rules > Edit inbound rules
4Delete any rule with Source 0.0.0.0/0 or ::/0
5Save rules

Check Code

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.ec2.ec2_securitygroup_allow_ingress_from_internet_to_all_ports import (
    ec2_securitygroup_allow_ingress_from_internet_to_all_ports,
)
from prowler.providers.aws.services.ec2.ec2_service import NetworkInterface
from prowler.providers.aws.services.ec2.lib.security_groups import check_security_group
from prowler.providers.aws.services.vpc.vpc_client import vpc_client


class ec2_securitygroup_allow_ingress_from_internet_to_any_port(Check):
    def execute(self):
        findings = []
        for security_group_arn, security_group in ec2_client.security_groups.items():
            # Only execute the check if the check ec2_securitygroup_allow_ingress_from_internet_to_all_ports has not failed
            if not ec2_client.is_failed_check(
                ec2_securitygroup_allow_ingress_from_internet_to_all_ports.__name__,
                security_group_arn,
            ):
                # 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}) does not have any port open to the Internet."
                    for ingress_rule in security_group.ingress_rules:
                        if check_security_group(
                            ingress_rule, "-1", any_address=True, all_ports=True
                        ):
                            self.check_enis(
                                report=report,
                                security_group_name=security_group.name,
                                security_group_id=security_group.id,
                                enis=security_group.network_interfaces,
                            )

                        if report.status == "FAIL":
                            break
                    findings.append(report)

        return findings

    def check_enis(
        self,
        report,
        security_group_name: str,
        security_group_id: str,
        enis: list[NetworkInterface],
    ):
        report.status_extended = f"Security group {security_group_name} ({security_group_id}) has at least one port open to the Internet but it is not attached to any network interface."
        for eni in enis:
            if eni.type in ec2_client.audit_config.get(
                "ec2_allowed_interface_types", ["api_gateway_managed", "vpc_endpoint"]
            ):
                report.status = "PASS"
                report.status_extended = f"Security group {security_group_name} ({security_group_id}) has at least one port open to the Internet and it is attached to an allowed network interface type ({eni.type})."
                continue
            if eni.attachment.instance_owner_id in ec2_client.audit_config.get(
                "ec2_allowed_instance_owners", ["amazon-elb"]
            ):
                report.status = "PASS"
                report.status_extended = f"Security group {security_group_name} ({security_group_id}) has at least one port open to the Internet and it is attached to an allowed network interface instance owner ({eni.attachment.instance_owner_id})."
                continue
            if eni.type not in ec2_client.audit_config.get(
                "ec2_allowed_interface_types", ["api_gateway_managed", "vpc_endpoint"]
            ):
                report.status = "FAIL"
                report.status_extended = f"Security group {security_group_name} ({security_group_id}) has at least one port open to the Internet but its network interface type ({eni.type}) is not allowed."
            elif eni.attachment.instance_owner_id not in ec2_client.audit_config.get(
                "ec2_allowed_instance_owners", ["amazon-elb"]
            ):
                report.status = "FAIL"
                report.status_extended = f"Security group {security_group_name} ({security_group_id}) has at least one port open to the Internet but its network interface instance owner ({eni.attachment.instance_owner_id}) is not allowed."
            else:
                report.status = "FAIL"
                report.status_extended = f"Security group {security_group_name} ({security_group_id}) has at least one port open to the Internet but neither its network interface type ({eni.type}) nor its network interface instance owner ({eni.attachment.instance_owner_id}) are allowed."
            if report.status == "FAIL":
                break