Back to scan results
Check 5 of 24

Open Ports / Exposed Services

We attempt a TCP connect on a curated list of high-risk ports. Anything that accepts a connection is reported. Web traffic ports (80, 443) are expected; database, admin, and legacy file-transfer ports almost never should be.

What this check probes

A short, fast TCP connect (SYN → SYN/ACK → RST) on each of the following — no payload sprayed, no banners grabbed beyond what arrives unsolicited:

  • 21 FTP, 23 Telnet — cleartext credentials, must never be on the public internet.
  • 22 SSH — fine for admin if locked down (key auth only, fail2ban), but flagged for review.
  • 25 / 465 / 587 SMTP — fine for mail servers, but a flag if you're not running mail.
  • 1433 Microsoft SQL Server, 1521 Oracle, 3306 MySQL/MariaDB, 5432 PostgreSQL — databases must never be reachable from the internet.
  • 3389 RDP — exposed RDP is the #1 ransomware entry point per multiple incident reports.
  • 5900 VNC — frequently no auth or weak password.
  • 6379 Redis, 11211 Memcached — both default to no authentication.
  • 27017 MongoDB, 9200 / 9300 Elasticsearch — historically default to no auth, frequent source of public data leaks.

Why this matters for PCI DSS

PCI DSS 4.0 Requirement 1.4.1: "NSCs are implemented between trusted and untrusted networks." That means your perimeter must block inbound traffic to every port that doesn't have a documented business need. Requirement 2.2.4 requires that only necessary services, protocols, and daemons are enabled.

Practically: a publicly reachable database is a one-step away from a full breach if any credential leaks, any default password exists, or any unpatched CVE applies. The PCI assessor will fail you on the open port alone — they don't need to prove exploitation.

How to fix it

Cloud (AWS/Azure/GCP) — fix at the security group / NSG level, which is the cheapest place to block. AWS example:

aws ec2 revoke-security-group-ingress \
    --group-id sg-0123456789abcdef \
    --protocol tcp --port 3306 --cidr 0.0.0.0/0

Replace with a rule allowing only your application servers' security group, or a VPN CIDR.

Linux server — bind the service to localhost so it can't accept external connections. For MySQL, edit /etc/mysql/my.cnf:

[mysqld]
bind-address = 127.0.0.1

For PostgreSQL, edit postgresql.conf: listen_addresses = 'localhost'.

Then add a host firewall belt to the suspenders:

sudo ufw default deny incoming
sudo ufw allow 22/tcp
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable

Windows — use Windows Firewall. The principle is the same: default-deny inbound, allow only the specific ports your application requires.

Verify externally with Shodan (search your IP) or run nmap -Pn -p- example.com from outside your network.

Fixed it? Re-run the scan to confirm.

Run scan again