Type something to search...
What is a subdomain takeover and how to prevent dangling DNS records?

What is a subdomain takeover and how to prevent dangling DNS records?

A subdomain takeover happens when one of your DNS records still points at an external resource, such as a cloud storage bucket, a hosting app or a load balancer, that you've deleted or never fully claimed, and someone else is able to claim that resource and serve their own content on your subdomain. The record that makes it possible is called a dangling DNS record. You prevent takeovers by removing DNS records before you delete the resources they point to, keeping an inventory of which records point where, auditing your zones regularly for targets that no longer exist, and using the domain verification features that cloud platforms provide.

It's one of the most common findings in security assessments, because it doesn't need any vulnerability in your code. It's simply a gap between two systems, your DNS and a third-party platform, that drift out of step over time. In this article you'll learn how dangling records arise, which kinds of records and services are affected, why a takeover is more serious than it first looks, and how to audit your own zones and build processes that stop dangling records appearing at all.

How a Dangling Record Arises

The usual story goes like this:

  1. A team creates a resource on a cloud platform, for example a static site that the platform serves at promo-2025.hostingplatform.example.
  2. They add a CNAME so the site appears on their own domain.
  3. The campaign ends. Someone deletes the site on the platform to save money or tidy up.
  4. Nobody removes the CNAME. It still points at promo-2025.hostingplatform.example, which no longer belongs to anyone.

The record left behind looks like this:

promo.example.com.  3600  IN  CNAME  promo-2025.hostingplatform.example.

At this point, promo.example.com is dangling. On many platforms, resource names are first come, first served. If the platform lets any customer create a resource with that freed-up name and attach the custom hostname promo.example.com to it, without proving they control the domain, then whoever does so gains control of what your subdomain shows.

Which Records Can Dangle

CNAMEs are the most common culprit, but they're not the only one.

Record typeHow it danglesExample
CNAMEPoints to a hostname for a deleted platform resourceA static site, app service or storage endpoint that was removed
A / AAAAPoints to a cloud IP address that has been releasedA public IP returned to the provider's pool after a server was shut down
NSDelegates a subdomain to a DNS zone that no longer existsA hosted zone deleted at a cloud DNS provider while the delegation remains
MXPoints to a mail service you no longer useA mailbox provider account was closed but the records remain

Dangling CNAMEs

These are the classic case. The record points to a name on a shared platform, such as a storage service, a static hosting service, a platform-as-a-service app, or a CDN. If the platform's resource names can be reused by other customers, and the platform doesn't require domain verification, a takeover is possible.

Dangling IP Addresses

Cloud providers recycle public IP addresses. If an A record points to an elastic or public IP you released, the provider may eventually assign that address to another customer. Their server then receives traffic meant for your subdomain. This is harder to exploit deliberately, because the new owner can't usually choose which IP they get, but it still leaves your subdomain under someone else's control.

Dangling NS Delegations

If you delegate dev.example.com to a hosted zone at a cloud DNS provider and later delete that zone, the delegation still points at the provider's nameservers. On some providers, another customer could create a zone for dev.example.com and, if it lands on the same nameservers, answer for it. This is particularly serious, because it hands over every name under that subdomain, not just one.

Why a Takeover Is Serious

A taken-over subdomain looks completely legitimate to users and browsers, because it really is your domain. Someone controlling it could:

  • Host phishing pages on a trusted domain, which also defeats users who have been trained to "check the address bar".
  • Obtain a valid TLS certificate for the subdomain, because they can pass domain validation by serving content on it.
  • Read cookies scoped to the parent domain. If your application sets cookies for .example.com, a page on any subdomain can receive them, which may include session cookies.
  • Bypass security policies such as Content Security Policy or CORS allowlists that trust *.example.com.
  • Damage your reputation with spam, malware or offensive content on your domain.

How to Find Dangling Records

The goal is to find every record that points outside your direct control and check that the target still exists and still belongs to you.

Step 1: Get a Full List of Records

Start with a complete export of each zone from your DNS provider. Don't rely on memory or a spreadsheet. Most providers offer a BIND-format export, and the major cloud providers let you list records through their CLIs. For example, with Route 53:

aws route53 list-resource-record-sets \
  --hosted-zone-id Z0123456789EXAMPLE \
  --query "ResourceRecordSets[?Type=='CNAME'].[Name, ResourceRecords[0].Value]" \
  --output text
promo.example.com.      promo-2025.hostingplatform.example
docs.example.com.       example.docs-host.example
assets.example.com.     d111111abcdef8.cloudfront.net

Step 2: Check Whether CNAME Targets Still Resolve

A CNAME whose target returns NXDOMAIN is an immediate red flag. Check it with dig:

dig promo.example.com A
;; ->>HEADER<<- opcode: QUERY, status: NXDOMAIN, id: 40221

;; ANSWER SECTION:
promo.example.com.      3600    IN      CNAME   promo-2025.hostingplatform.example.

The answer contains your CNAME, but the status is NXDOMAIN, meaning the target name no longer exists. That record is dangling.

Not every dangling record produces NXDOMAIN. Some platforms resolve every name under their domain, then show a "no such site" page. So a target that resolves isn't automatically safe, which is why the inventory step below matters.

Step 3: Automate the Check

This Python script reads a list of names, follows each CNAME, and reports targets that don't resolve. It uses dnspython:

#!/usr/bin/env python3
"""Report CNAME records whose targets no longer resolve."""
import sys

import dns.exception
import dns.resolver

resolver = dns.resolver.Resolver()
resolver.lifetime = 5.0


def cname_target(name):
    try:
        answer = resolver.resolve(name, "CNAME")
        return answer[0].target.to_text()
    except (dns.resolver.NoAnswer, dns.resolver.NXDOMAIN):
        return None


def resolves(name):
    for rtype in ("A", "AAAA"):
        try:
            resolver.resolve(name, rtype)
            return True
        except (dns.resolver.NoAnswer, dns.resolver.NXDOMAIN):
            continue
    return False


with open(sys.argv[1]) as f:
    names = [line.strip() for line in f if line.strip() and not line.startswith("#")]

for name in names:
    try:
        target = cname_target(name)
        if target is None:
            continue
        if not resolves(target):
            print(f"DANGLING? {name} -> {target} (target does not resolve)")
    except dns.exception.DNSException as exc:
        print(f"ERROR     {name}: {exc}")
pip install dnspython
python3 find_dangling.py subdomains.txt
DANGLING? promo.example.com -> promo-2025.hostingplatform.example. (target does not resolve)

Run it on a schedule against an up-to-date export of your zones, and alert on any new finding.

Step 4: Check Delegated Subdomains

For NS delegations, ask each delegated nameserver whether it actually answers for the subdomain:

for ns in $(dig dev.example.com NS +short); do
  printf '%-36s' "$ns"
  dig @"$ns" dev.example.com SOA +norecurse | grep -oE 'status: [A-Z]+'
done
ns-1234.awsdns-26.org.              status: REFUSED
ns-567.awsdns-07.net.               status: REFUSED

REFUSED or SERVFAIL from every delegated server means the zone they're supposed to host no longer exists there. Remove the delegation, or recreate the zone, straight away.

Step 5: Check A Records Against Your Inventory

For A and AAAA records pointing at cloud IP ranges, compare them with the addresses actually allocated to your accounts. On AWS, for example:

aws ec2 describe-addresses --query 'Addresses[].PublicIp' --output text | tr '\t' '\n' | sort > owned.txt
while read -r name; do
  dig +short "$name" A
done < names.txt | grep -E '^[0-9.]+$' | sort -u > published.txt
comm -13 owned.txt published.txt

The loop looks up every name in names.txt, and the grep keeps only IPv4 addresses, dropping any CNAME targets that dig +short prints along the way. The comm command prints addresses that are published in your DNS but not in your list of owned IPs. Some will be legitimate, such as addresses from other providers or load balancers, but each one should be explained.

How to Prevent Dangling Records

Detection catches problems after they happen. Prevention is about process.

Remove DNS First, Then Delete the Resource

Make it a rule: when you decommission anything, remove the DNS record first, wait for its TTL, and only then delete the cloud resource. That order means there's never a moment when your record points at something you don't own.

Build this into your runbooks and change templates, and into automation if you have it.

Manage DNS and Resources Together

The most reliable fix is to create DNS records in the same code as the resources they point to. With Terraform, a record that references a resource is destroyed along with it:

resource "aws_s3_bucket" "promo" {
  bucket = "promo.example.com"
}

resource "aws_s3_bucket_website_configuration" "promo" {
  bucket = aws_s3_bucket.promo.id

  index_document {
    suffix = "index.html"
  }
}

resource "aws_route53_record" "promo" {
  zone_id = var.zone_id
  name    = "promo.example.com"
  type    = "CNAME"
  ttl     = 300
  records = [aws_s3_bucket_website_configuration.promo.website_endpoint]
}

Because the record depends on the bucket's website configuration, running terraform destroy on this module removes the record as well. Terraform also destroys dependent resources before the ones they depend on, so the DNS record goes before the bucket.

Use Platform Domain Verification

Many platforms now protect against takeovers by requiring proof that you control a domain before letting anyone attach it. Use these features wherever they exist:

  • GitHub Pages lets you verify a domain for your account or organisation, which prevents other users from using it with their Pages sites.
  • Azure App Service supports a TXT record at asuid.<subdomain> containing a domain verification ID. Azure checks it when a custom domain is added, so another subscription can't simply reuse your hostname.
  • Other platforms use a TXT record or an HTTP challenge for the same purpose.

Verification records should stay in place for as long as you use the platform.

Keep an Inventory

Maintain a list of every record that points to an external service, along with the owner and the purpose. A simple table is enough to start:

NameTypeTargetServiceOwner
docs.example.comCNAMEexample.docs-host.exampleDocumentation hostProduct team
assets.example.comCNAMEd111111abcdef8.cloudfront.netCDNPlatform team
dev.example.comNSCloud DNS zoneDevelopment environmentEngineering

When a service is retired, the inventory tells you exactly which records go with it.

Limit Who Can Create Records

Fewer people creating ad hoc records means fewer forgotten ones. Restrict DNS write access, use pull requests for DNS changes, and require an owner field for new records.

Reduce the Impact If a Takeover Happens

Defence in depth limits what a taken-over subdomain can do:

  • Scope cookies to the exact host, such as www.example.com, rather than the whole domain, and use the __Host- cookie prefix where you can.
  • Avoid wildcard trust in CORS policies and Content Security Policy.
  • Use CAA records to restrict certificate issuance to the CAs you use. This doesn't stop a takeover, but it narrows the options.
  • Monitor Certificate Transparency logs for certificates issued for your subdomains that you didn't request.

What to Do If You Find a Dangling Record

  1. Remove the record immediately, or point it back at a resource you control.
  2. Check whether it's already been claimed. Visit the subdomain and look for content you don't recognise, and search Certificate Transparency logs for recent certificates on that name.
  3. If it was taken over, remove the DNS record, report the abuse to the platform, revoke any certificates issued to the attacker, and review whether cookies or sessions on the parent domain could have been exposed.
  4. Find out how it happened, and fix the decommissioning process that left it behind.

FAQ: Subdomain Takeover

A dangling DNS record is one that points to a resource you no longer control, such as a deleted cloud app, a released IP address or a removed hosted zone. It leaves your subdomain pointing at something another person might be able to claim.

CNAME records are the most common cause, but A and AAAA records pointing to released cloud IPs, NS records delegating to deleted zones, and MX records for closed mail services can all leave subdomains exposed.

Yes. Whoever controls the content on the subdomain can usually pass a certificate authority's domain validation, so the site can show a valid padlock. That's one reason takeovers are so effective for phishing.

Run automated checks at least weekly, and every time you decommission a service. Continuous monitoring is better for large organisations with many teams creating records.

No. DNSSEC proves your records are genuine, but in a takeover your genuine record is the problem, because it points at a resource someone else now controls.

Remove the DNS record first, wait for its TTL to expire, then delete the cloud resource. That way your subdomain never points at something you don't own.


Conclusion

A subdomain takeover isn't a bug in your application. It's a gap between your DNS and a platform you've stopped using, where a record keeps pointing at a resource that someone else can claim. CNAMEs to deleted cloud resources are the classic case, but released IPs and deleted delegated zones create the same risk.

Prevention is mostly about process. Remove DNS records before you delete resources, manage records alongside the infrastructure they point to, use platform domain verification, and keep an inventory of external targets. Back that up with regular automated audits, and you'll catch the occasional dangling record long before anyone else does.

Tags :
Share :

Related Posts

What is the difference between an A record and a CNAME record?

What is the difference between an A record and a CNAME record?

The difference between an A record and a CNAME record is what they point to. An A record points a hostname directly at an IPv4 address, such

Dive Deeper
What are the best DNS providers for websites?

What are the best DNS providers for websites?

The best DNS providers for most websites are Cloudflare for a fast, free, easy starting point, Amazon Route 53 if you already run on AWS, **G

Dive Deeper
What are the best public DNS resolvers?

What are the best public DNS resolvers?

The best public DNS resolvers for most people are Cloudflare (1.1.1.1) for speed and privacy, Google Public DNS (8.8.8.8) for reliability and

Dive Deeper