Back to Checks
aws

Network ACL does not allow ingress from the Internet to TCP port 3389 (RDP)

ec2_networkacl_allow_ingress_tcp_port_3389
Service: ec2Severity: medium
OfficialBuilt-inVerified
Categories:internet-exposed
Resource Type:AwsEc2NetworkAcl

VPC network ACLs with inbound rules allowing RDP on TCP 3389 from 0.0.0.0/0 are identified.

Assessment focuses on subnet-level ACL entries that permit this traffic.

Risk

Internet-exposed RDP enables password spraying, brute force, and exploitation of RDP flaws to gain remote control. Allowing it at the subnet layer weakens defense in depth-a misconfigured security group or route can expose instances-leading to data exfiltration, privilege escalation, and ransomware, impacting confidentiality and integrity.

Run this check with Prowler

Run in Prowler Cloud
Run
prowler aws --checks ec2_networkacl_allow_ingress_tcp_port_3389

Recommendation

Enforce least privilege: do not allow TCP 3389 from 0.0.0.0/0 in network ACLs.

  • Restrict RDP to specific admin IP ranges
  • Prefer bastion hosts or Session Manager over direct RDP
  • Use private subnets and layer controls for defense in depth

Remediation

CLI

aws ec2 delete-network-acl-entry --network-acl-id <NETWORK_ACL_ID> --ingress --rule-number <RULE_NUMBER>

Terraform

# Deny inbound RDP (TCP 3389) from the Internet on an existing NACL
resource "aws_network_acl_rule" "<example_resource_name>" {
  network_acl_id = "<example_resource_id>"
  rule_number    = 1                 # Critical: lower than any allow so deny takes precedence
  egress         = false             # Ingress rule
  protocol       = "tcp"
  rule_action    = "deny"            # Critical: block the traffic
  cidr_block     = "0.0.0.0/0"       # Critical: Internet source
  from_port      = 3389              # Critical: RDP port
  to_port        = 3389
}

NativeIaC

# CloudFormation: deny inbound RDP (TCP 3389) from the Internet on an existing NACL
Resources:
  NetworkAclDenyRDP:
    Type: AWS::EC2::NetworkAclEntry
    Properties:
      NetworkAclId: <example_resource_id>
      RuleNumber: 1                 # Critical: ensure this deny is evaluated before any allow
      Protocol: 6                   # TCP
      Egress: false                 # Ingress rule
      RuleAction: deny              # Critical: block the traffic
      CidrBlock: 0.0.0.0/0          # Critical: Internet source
      PortRange:
        From: 3389                  # Critical: RDP port
        To: 3389

Other

1In the AWS Console, go to VPC > Network ACLs and select the ACL used by the affected subnet(s)
2Open the Inbound rules tab
3Find any rule allowing TCP port 3389 (RDP) from 0.0.0.0/0 or ::/0
4Select that rule and click Delete, then Save
5If you must keep broad allows, instead click Edit inbound rules and add a new rule with a lower rule number that Denies TCP 3389 from 0.0.0.0/0, then Save

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.lib.network_acls import check_network_acl


class ec2_networkacl_allow_ingress_tcp_port_3389(Check):
    def execute(self):
        findings = []
        tcp_protocol = "6"
        check_port = 3389
        for arn, network_acl in ec2_client.network_acls.items():
            if (
                ec2_client.provider.scan_unused_services
                or network_acl.region in ec2_client.regions_with_sgs
            ):
                report = Check_Report_AWS(
                    metadata=self.metadata(), resource=network_acl
                )
                # If some entry allows it, that ACL is not securely configured
                if check_network_acl(network_acl.entries, tcp_protocol, check_port):
                    report.status = "FAIL"
                    report.status_extended = f"Network ACL {network_acl.name if network_acl.name else network_acl.id} has Microsoft RDP port 3389 open to the Internet."
                    findings.append(report)
                else:
                    report.status = "PASS"
                    report.status_extended = f"Network ACL {network_acl.name if network_acl.name else network_acl.id} does not have Microsoft RDP port 3389 open to the Internet."
                    findings.append(report)

        return findings