Back to Checks
cloudflare

DNS records do not expose internal IP addresses

dns_record_no_internal_ip
Service: dnsSeverity: high
OfficialBuilt-inVerified
Categories:internet-exposed
Resource Type:DNSRecord

Cloudflare DNS records are assessed for internal IP exposure by checking if A or AAAA records point to private, loopback, or reserved IP addresses which could leak internal network structure.

Risk

DNS records exposing internal IP addresses leak sensitive network information.

  • Confidentiality: reveals internal network topology and addressing schemes to attackers
  • Integrity: provides reconnaissance data for targeted attacks on internal infrastructure
  • Availability: internal IPs in public DNS may indicate misconfiguration affecting service routing

Run this check with Prowler

Run in Prowler Cloud
Run
prowler cloudflare --checks dns_record_no_internal_ip

Recommendation

Remove internal IP addresses from public DNS records.

  • Use split-horizon DNS for internal service resolution
  • Ensure DNS records only contain publicly routable IP addresses
  • Review DNS records after network changes or migrations
  • Consider using Cloudflare Access for secure internal service access

Remediation

Other

1Log in to the Cloudflare dashboard and select your account and domain
2Go to DNS > Records
3Identify A/AAAA records pointing to internal IP addresses
4Update records to point to public IP addresses or remove if not needed
5Use split-horizon DNS if internal resolution is required

Check Code

import ipaddress

from prowler.lib.check.models import Check, CheckReportCloudflare
from prowler.providers.cloudflare.services.dns.dns_client import dns_client


class dns_record_no_internal_ip(Check):
    """Ensure that DNS records do not expose internal or private IP addresses.

    Public DNS records should only contain publicly routable IP addresses.
    Exposing internal, private, loopback, or link-local addresses in DNS records
    can leak information about internal network infrastructure, potentially
    aiding attackers in reconnaissance and targeted attacks against internal
    systems.
    """

    def execute(self) -> list[CheckReportCloudflare]:
        """Execute the internal IP address exposure check.

        Iterates through all A and AAAA DNS records and checks if they contain
        private, loopback, link-local, or reserved IP addresses that should not
        be exposed publicly.

        Returns:
            A list of CheckReportCloudflare objects with PASS status if the
            record points to a public IP address, or FAIL status if it exposes
            an internal IP address.
        """
        findings = []

        for record in dns_client.records:
            # Only check A and AAAA records
            if record.type not in ("A", "AAAA"):
                continue

            report = CheckReportCloudflare(
                metadata=self.metadata(),
                resource=record,
            )

            is_internal = self._is_internal_ip(record.content)

            if not is_internal:
                report.status = "PASS"
                report.status_extended = (
                    f"DNS record {record.name} ({record.type}) points to "
                    f"public IP address {record.content}."
                )
            else:
                report.status = "FAIL"
                report.status_extended = (
                    f"DNS record {record.name} ({record.type}) exposes "
                    f"internal IP address {record.content} - information disclosure risk."
                )
            findings.append(report)

        return findings

    def _is_internal_ip(self, ip_str: str) -> bool:
        """Check if IP address is internal/private."""
        try:
            ip = ipaddress.ip_address(ip_str)
            # Check for private, loopback, link-local, or reserved addresses
            return (
                ip.is_private
                or ip.is_loopback
                or ip.is_link_local
                or ip.is_reserved
                or ip.is_unspecified
            )
        except ValueError:
            # Invalid IP format, assume not internal
            return False