EC2.13 is an AWS Security Hub CSPM control that fails when a security group allows inbound traffic to port 22 (SSH) from 0.0.0.0/0 or ::/0, meaning any address on the Internet. Fix it by revoking those rules, allowing SSH only from specific admin or VPN ranges, or better, reaching instances through Session Manager with no inbound SSH rule.
What the scanner is actually detecting
These are configuration checks against the security group object (AWS::EC2::SecurityGroup), not a port scan. Security Hub evaluates the group’s inbound rules through AWS Config rules, so the result depends on each rule’s source range, not on whether anything answers on the port.
| Scanner | Finding title | Severity | Underlying check |
|---|---|---|---|
| AWS Security Hub CSPM | [EC2.13] Security groups should not allow ingress from 0.0.0.0/0 or ::/0 to port 22 | High | AWS Config rule restricted-ssh; also mapped to CIS AWS Foundations Benchmark v1.2.0 control 4.1 |
| AWS Security Hub CSPM | [EC2.19] Security groups should not allow unrestricted access to ports with high risk | Critical | AWS Config rule restricted-common-ports (created as vpc-sg-restricted-common-ports) |
| Microsoft Defender for Cloud (AWS connector) | Security groups should not allow ingress from 0.0.0.0/0 to port 22 | High | Defender recommendation for AWS security groups |
| Microsoft Defender for Cloud (AWS connector) | Security groups should not allow unrestricted access to ports with high risk | Medium | Defender recommendation for AWS security groups |
EC2.19 checks a fixed list of TCP ports that you cannot customize: 20, 21, 22, 23, 25, 110, 135, 143, 445, 1433, 1434, 3000, 3306, 3389, 4333, 5000, 5432, 5500, 5601, 8080, 8088, 8888, 9200 and 9300. Because 22 is on that list, one world-open SSH rule fails EC2.13 and EC2.19 at the same time. Defender’s list is shorter and omits 3000, 5000, 8088 and 8888, so the two tools can disagree about the same group. If you are new to control-based checks like these, our explainer on cloud security posture management (CSPM) covers how they differ from host vulnerability scanning.
Real-world risk
Any public address answering on port 22 is found by automated Internet-wide scanning and receives continuous login attempts. With key-only authentication and a patched OpenSSH, those guesses rarely succeed. The remaining risk is a pre-authentication flaw in sshd, such as regreSSHion (CVE-2024-6387), a leaked private key, or an image where someone re-enabled password logins. The other EC2.19 ports are often worse: databases, SMB and search clusters exposed to 0.0.0.0/0 depend entirely on the application’s own authentication, which in development setups is frequently weak or absent.
Context matters. The rule only exposes an instance when the group is attached to a network interface with a public IPv4 address, or an IPv6 address in a subnet routed to an internet gateway. A private-subnet instance is not reachable from the Internet, but a 0.0.0.0/0 source still admits every internal, peered and VPN-connected network. To weigh that context across a large backlog, see how to prioritize cloud findings by actual exposure.
How to confirm it
The commands below use bash quoting; run them in AWS CloudShell or a Linux or macOS shell. List every world-open inbound rule in a Region:
aws ec2 describe-security-group-rules --region eu-central-1
--query "SecurityGroupRules[?IsEgress==`false` && (CidrIpv4=='0.0.0.0/0' || CidrIpv6=='::/0')].[GroupId,SecurityGroupRuleId,IpProtocol,FromPort,ToPort,CidrIpv4,CidrIpv6]"
--output table
A row fails EC2.13 when the protocol is tcp and 22 falls between FromPort and ToPort, or when the protocol is -1 (all traffic, shown with ports of -1). Compare the remaining rows against the EC2.19 port list. Then see which network interfaces, and therefore which instances, use a flagged group:
aws ec2 describe-network-interfaces
--filters Name=group-id,Values=sg-0123456789abcdef0
--query "NetworkInterfaces[].[NetworkInterfaceId,Attachment.InstanceId,Association.PublicIp]"
--output table
To pull the failing groups straight from Security Hub (swap EC2.13 for EC2.19 as needed):
aws securityhub get-findings
--filters '{"ComplianceSecurityControlId":[{"Value":"EC2.13","Comparison":"EQUALS"}],"ComplianceStatus":[{"Value":"FAILED","Comparison":"EQUALS"}],"RecordState":[{"Value":"ACTIVE","Comparison":"EQUALS"}]}'
--query "Findings[].Resources[].Id" --output text
Finally, test from a network outside AWS with nc -vz PUBLIC-IP 22. A successful connection confirms the port is reachable.
How to fix it
Save the current rules first so you can roll back:
aws ec2 describe-security-group-rules
--filters Name=group-id,Values=sg-0123456789abcdef0 > sg-0123456789abcdef0-rules.json
Option 1: keep SSH, restrict the source
Add the narrow rule before removing the wide one:
aws ec2 authorize-security-group-ingress --group-id sg-0123456789abcdef0
--ip-permissions 'IpProtocol=tcp,FromPort=22,ToPort=22,IpRanges=[{CidrIp=198.51.100.0/24,Description=SSH from admin VPN}]'
Then revoke the IPv4 and IPv6 world-open rules:
aws ec2 revoke-security-group-ingress --group-id sg-0123456789abcdef0
--protocol tcp --port 22 --cidr 0.0.0.0/0
aws ec2 revoke-security-group-ingress --group-id sg-0123456789abcdef0
--ip-permissions 'IpProtocol=tcp,FromPort=22,ToPort=22,Ipv6Ranges=[{CidrIpv6=::/0}]'
Property values must match the existing rule exactly. In a non-default VPC a mismatch returns InvalidPermission.NotFound and revokes nothing; in a default VPC it returns no error, and the output lists the rules that were not revoked. For port ranges or all-traffic rules, revoke by rule ID from the query above:
aws ec2 revoke-security-group-ingress --group-id sg-0123456789abcdef0
--security-group-rule-ids sgr-0123456789abcdef0
If many groups need the same admin ranges, put them in a customer-managed prefix list and reference it with PrefixListIds instead of repeating CIDRs.
Option 2: Session Manager, no inbound port at all
Session Manager provides shell access without open inbound ports, bastion hosts or SSH keys, with access granted through IAM. The instance needs SSM Agent, an instance profile that includes the AmazonSSMManagedInstanceCore managed policy, and outbound HTTPS (443) to the ssm, ssmmessages and ec2messages endpoints, directly or through interface VPC endpoints. Your workstation needs the Session Manager plugin for the AWS CLI.
aws ec2 associate-iam-instance-profile --instance-id i-0123456789abcdef0
--iam-instance-profile Name=SSMInstanceProfile
aws ssm describe-instance-information
--filters "Key=InstanceIds,Values=i-0123456789abcdef0"
aws ssm start-session --target i-0123456789abcdef0
If tools still need real SSH or SCP, tunnel them through Session Manager with this entry in ~/.ssh/config (SSM Agent 2.3.672.0 or later on the instance):
# SSH over Session Manager
Host i-* mi-*
ProxyCommand sh -c "aws ssm start-session --target %h --document-name AWS-StartSSHSession --parameters 'portNumber=%p'"
User ec2-user
Session logging is not available for SSH or port-forwarding sessions. Standard sessions run as ssm-user, which has root or administrator permissions by default, so scope ssm:StartSession in IAM carefully. Once access works, revoke every port 22 rule on the group.
Option 3: EC2 Instance Connect Endpoint
For private instances where you want native SSH, create an endpoint in the VPC and let only its security group reach port 22:
aws ec2 create-instance-connect-endpoint --subnet-id subnet-0123456789abcdef0
--security-group-ids sg-0fedcba9876543210
aws ec2 authorize-security-group-ingress --group-id sg-0123456789abcdef0
--protocol tcp --port 22 --source-group sg-0fedcba9876543210
aws ec2 authorize-security-group-egress --group-id sg-0fedcba9876543210
--ip-permissions 'IpProtocol=tcp,FromPort=22,ToPort=22,UserIdGroupPairs=[{GroupId=sg-0123456789abcdef0}]'
aws ec2-instance-connect ssh --instance-id i-0123456789abcdef0
--os-user ec2-user --connection-type eice
The last command needs AWS CLI version 2. The instance keeps a port 22 rule, but its source is a security group rather than 0.0.0.0/0 or ::/0, which passes EC2.13.
EC2.19: the other high-risk ports
Apply the same pattern to each world-open rule on the list. Replace the CIDR with a source security group where the traffic comes from another tier, for example a database that only the application servers should reach:
aws ec2 authorize-security-group-ingress --group-id sg-DATABASE
--protocol tcp --port 5432 --source-group sg-APPTIER
aws ec2 revoke-security-group-ingress --group-id sg-DATABASE
--protocol tcp --port 5432 --cidr 0.0.0.0/0
For RDP on 3389, Session Manager port forwarding and EC2 Instance Connect Endpoint both work. If the rule is defined in Terraform or CloudFormation, change it there as well, or the next deployment puts it back.
How to verify the fix and rescan
- Re-run the describe-security-group-rules query. No rows should cover port 22 or any EC2.19 port.
- From outside AWS, open a new connection with nc -vz PUBLIC-IP 22. It should time out.
- Re-run the get-findings query and confirm the group has dropped out. Both controls are change triggered and periodic, so editing the group starts a new evaluation. If AWS Config uses daily recording, the update can wait until that 24-hour period completes. When the compliance status becomes PASSED, Security Hub sets the workflow status to RESOLVED automatically.
- Defender for Cloud clears its recommendation after its next assessment of the AWS connector, not the moment you save the rule.
What can break and how to roll back
- Your own session. When a group allows 22 from 0.0.0.0/0 and outbound traffic to 0.0.0.0/0, those SSH flows are untracked, and removing the rule drops existing sessions immediately. Get Session Manager or the new narrow rule working first.
- Shared groups. One group can be attached to many interfaces, including Auto Scaling instances. Check usage with describe-network-interfaces before editing.
- Automation. CI/CD runners with changing egress addresses, configuration management over SSH, SFTP partners and vendor support sessions lose access.
To roll back, re-authorize the specific rule you need from the saved JSON. If you must restore access in a hurry, add your current address as a /32 rather than reopening 0.0.0.0/0.
Common false positive reasons
- No real exposure. The group is unattached, or its instances have no public IP. The rule is still world-open as written, so tighten it or document why it stays.
- Blocked elsewhere. A network ACL or AWS Network Firewall drops the traffic. These controls read only the security group, so the finding remains until the rule changes.
- Intended exposure. A public SFTP service on 22 or a mail server on 25 is reported correctly. That is accepted risk, not a false positive: set the finding’s workflow status to SUPPRESSED with a note explaining why.
- Stale evaluation caused by daily AWS Config recording, or the different Defender and Security Hub port lists described above.
FAQ
My instances only accept SSH keys. Does EC2.13 still fail?
Yes. The control evaluates the rule’s source range, not how sshd authenticates. Key-only login reduces the risk but leaves the port reachable by anyone.
Does an EC2 Instance Connect Endpoint rule on port 22 fail EC2.13?
No, as long as the source is the endpoint’s security group or a specific range, not 0.0.0.0/0 or ::/0.
Can I change the EC2.19 port list?
No, it is fixed. If you need your own allowlist, EC2.18 checks world-open rules against authorized ports that you can configure (80 and 443 by default).
My VPC has no IPv6. Do I still need to remove the ::/0 rule?
Yes. The control fails on the rule itself, and the rule becomes live the moment an IPv6 range is added to the VPC.
Tracking this finding across many hosts
Security Hub’s cross-Region aggregation, combined with an organization-wide administrator account, gives you one list of failing groups across accounts. If you also consolidate findings in SITEY, a self-hosted vulnerability management platform that imports findings from 16 scanners, note that it merges duplicates per scanner, not across scanners, so the same open port reported by two different tools stays as two findings. Its AI triage can suggest false positives with evidence, but a person makes the final call.
Sources
- AWS Security Hub CSPM User Guide: Security Hub CSPM controls for Amazon EC2
- Microsoft Learn: Reference table for all networking security recommendations
- AWS CLI Command Reference: revoke-security-group-ingress
- Amazon EC2 User Guide: Security group connection tracking
- AWS Systems Manager User Guide: Session Manager