Remediation Guides

EC2.13: How to Fix Security Groups Open to Port 22 (and EC2.19 High-Risk Ports)

26 September 2026 8 min read

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

SITEY closes the loop, not just the report.Discover, validate, fix and verify in your own infrastructure.

See pricing