Dangling DNS Records: Inventory First, Then Triage
Share

Dangling DNS: Finding the CNAMEs That Point Nowhere

The lookup comes back clean.

assets.example.com answers NOERROR with a single CNAME pointing at a cloud storage endpoint. No SERVFAIL. No timeout. Nothing in the zone is malformed, and no DNS health check will say a word about it.

Now assume the storage bucket that endpoint names was deleted eleven months ago, in a project wind-down nobody wrote down.

The record still answers. That is the entire problem.

What a dangling record is, and what it is not

Start with the record semantics. RFC 1035 Section 3.3.1 defines the CNAME RDATA as a single domain-name "which specifies the canonical or primary name for the owner. The owner name is an alias." Section 3.2.2 of the same document assigns CNAME the decimal type code 5. An alias, a target, nothing else. Every specification cited here is a published RFC, not an Internet-Draft.

What a resolver does when it meets one is specified in RFC 1034, Section 3.6.2.

"CNAME RRs cause special action in DNS software. When a name server fails to find a desired RR in the resource set associated with the domain name, it checks to see if the resource set consists of a CNAME record with a matching class. If so, the name server includes the CNAME record in the response and restarts the query at the domain name specified in the data field of the CNAME record. The one exception to this rule is that queries which match the CNAME type are not restarted."
RFC 1034: Domain Names — Concepts and Facilities, Section 3.6.2, IETF, November 1987

Read that again with a deprovisioned target in mind. The server finds a CNAME. It returns the CNAME. The query restarts at the canonical name. Every step is what the standard requires, and the answer that reaches the client is a correct answer.

This is not a DNS fault. It is a state at a service provider, one layer above the protocol, and the DNS has no way to observe it. Records describe names. Whether anything is still running behind the name is not a fact the DNS carries, has ever carried, or was designed to carry.

Microsoft's Azure security documentation is the clearest first-party description of the condition, and it puts the contradiction in one sentence.

"If the CNAME record isn't removed, it's advertised as an active domain but doesn't route traffic to an active Azure resource. You now have a "dangling" DNS record."
Prevent dangling DNS entries and avoid subdomain takeover, Microsoft Learn, July 20, 2026

Advertised as active. Routing nowhere. Both true at the same time, which is why the condition survives audits that only look at whether records resolve.

Two more rules in RFC 1034 Section 3.6.2 matter later, when you get to fixing things. The first is exclusivity: "If a CNAME RR is present at a node, no other data should be present; this ensures that the data for a canonical name and its aliases cannot be different." You cannot patch around a dangling CNAME by putting an A record beside it. The record has to be removed or replaced.

The second is chaining. RFC 1034 says "CNAME chains should be followed and CNAME loops signalled as an error." Production targets chain routinely (a vanity name to a CDN edge to a platform hostname), and the hop with nothing behind it may not be the first one. Inventory the whole chain.

The check most guidance gets backwards

Nearly every article on this subject tells you to resolve the CNAME target and look for a provider error string. That test has real uses. It is second on the list, not first.

The two cloud vendors with the most to lose from getting this wrong both recommend the opposite check. Microsoft's discovery guidance is to review your DNS records regularly and confirm that every subdomain maps to an Azure resource that exists and that you own. The second half is the one people skip, and Microsoft states it flatly: "Confirm that you own all resources that your DNS subdomains are targeting." The same page recommends maintaining a service catalogue of FQDN endpoints and the application owner for each.

AWS arrives in the same place from the other direction. In a June 2026 AWS Security Blog post, Matt Gurr, Ariam Michael, Geoff Sweet and Luis Pastor describe a subdomain takeover as what follows when you delete the underlying resource and someone else creates a new resource with the same name, using the DNS records still pointing at it. Their recommended detection is AWS Config monitoring Route 53 CNAME records against the resources that actually exist in the account. Not a probe. A reconciliation.

OWASP's Subdomain Takeover Prevention Cheat Sheet treats the same idea as a control rather than a scan: keep a documented mapping between DNS records and the cloud resources they point to, with an owner, a business justification and an expected decommissioning date for each.

The inversion is the whole methodology. "Does the target answer?" is a question about somebody else's infrastructure, and the answer moves with provider behaviour, caching and edge configuration. "Do I still own the target?" is a question about your own accounts. It has a definite answer, and you are the only person entitled to it.

MITRE ATT&CK explains why the reconciliation lands on your desk. The adversary behaviour is catalogued as sub-technique T1584.001, Compromise Infrastructure: Domains, under the Resource Development tactic (TA0042), version 1.4, last modified 12 May 2026.

"Subdomain hijacking can occur when organizations have DNS entries that point to non-existent or deprovisioned resources. In such cases, an adversary may take control of a subdomain to conduct operations with the benefit of the trust associated with that domain."
Compromise Infrastructure: Domains (T1584.001), MITRE ATT&CK, May 12, 2026

MITRE's assessment of preventive controls for it is short: "This technique cannot be easily mitigated with preventive controls since it is based on behaviors performed outside of the scope of enterprise defenses and controls." No sensor of yours sits on the path. Periodic self-inventory is the control.

Enumerating your own names

Four sources, ordered by how much they are worth to someone auditing a domain they run.

1. Your own zone. Export it from your DNS provider. Two clicks, usually. It is the correct answer for a self-audit because it is authoritative and complete, which nothing else on this list is. The rest of the list exists to catch names your zone used to contain, or names published by a team that never told you.

2. Certificate Transparency logs. A hostname that was ever issued a publicly trusted certificate is in the logs, and RFC 6962 Section 3 forbids gating access to them: "Log operators MUST NOT impose any conditions on retrieving or sharing data from the log." That makes CT a lawful, public enumeration input for names in your own estate. Our companion article on what a public zone reveals takes CT apart properly; here it is only a feed.

3. AXFR, which will almost certainly be refused. Zone transfer looks like the obvious enumeration route and is not one. RFC 5936 Section 5 records why: "A zone administrator has the option to restrict AXFR access to a zone. This was not envisioned in the original design of the DNS but has emerged as a requirement as the DNS has evolved." It goes further on defaults: "A general-purpose implementation SHOULD NOT have a default policy for AXFR requests to be "open to all"". So stop reaching for AXFR and go download your own zone.

4. Passive DNS aggregators. Supplementary, and useful in the same way CT is: they surface names that existed once. Treat anything they return as a lead to check against your zone, not as evidence.

The output you want is boring and tabular. Owner name, target, provider.

; the artefact you are building: owner name -> target, grouped by provider suffix assets.example.com. 300 IN CNAME legacy-assets.s3.amazonaws.com. files.example.com. 300 IN CNAME c.storage.googleapis.com. status.example.com. 300 IN CNAME example-org.github.io. app-uat.example.com. 300 IN CNAME contoso-uat.azurewebsites.net. cdn.example.com. 300 IN CNAME d111111abcdef8.cloudfront.net. edge.example.com. 300 IN CNAME example.azureedge.net.
A CNAME inventory maps names to targets; ownership of the target is checked elsewhere

The zone tells you where a name points. It cannot tell you whether anything is still standing at the other end.

Grouping by provider suffix is the step that makes the ownership check tractable. Microsoft publishes the Azure patterns worth grouping on: *.azurefd.net, *.blob.core.windows.net, *.azureedge.net, *.cloudapp.azure.com, *.trafficmanager.net, *.azurecontainer.io, *.azure-api.net and *.azurewebsites.net. Google Cloud documents a fixed shape for its own case: a CNAME used for a domain-named bucket must have c.storage.googleapis.com as the hostname portion, and CNAMEs cannot be used at the apex. Once the list is grouped, each group is one console to open.

If you need the mechanics of running these queries, we covered them in DNS Lookup Explained, and this article will not re-teach dig.

Build The CNAME Half Of The Inventory

DNSai's CNAME view discovers subdomains from Certificate Transparency, queries them over DNS-over-HTTPS, and keeps only the names that currently answer with a CNAME record. Each hit is chain-resolved to a maximum of 10 hops, with the chain depth shown, and the terminal IP address appended in brackets only when the chain ends in an A record. A row with no bracketed address means the chain did not terminate in an address. That is a starting point for manual triage, never a finding. Runs are capped at 100 records and 45 seconds, and the name list is seeded from public logs, so it is not exhaustive; your zone export is. DNSai does not contact CNAME targets over HTTP, does not match provider error fingerprints, and does not test whether a target is claimable. The triage is yours to do.

Run A CNAME Lookup →

One deliberate behaviour is worth knowing before you use the subdomain view: it performs no DNS resolution and returns names that do not resolve. That is on purpose. In an audit, a name that stopped answering is often more interesting than one that still does.

Triage: three questions, in this order

You now have a list. It is not a list of vulnerabilities, and anyone who tells you otherwise is selling something. Work it in order.

Question one: do I still own the target? This is the ownership reconciliation above, and it is the only question with an authoritative answer. Microsoft ships a first-party PowerShell tool for the Azure side, Get-DanglingDnsRecords, described as follows: "This tool helps you list all domains with a CNAME associated with an existing Azure resource that you created on your subscriptions or tenants." Read the scope carefully. It matches your DNS against resources you created, across nine Azure resource types. It is an inventory reconciliation with a command-line interface, not a scanner.

Question two: how does the target behave? There is no single test here, and that is the honest answer rather than a hedge. Some deprovisioned targets return NXDOMAIN. Some resolve perfectly and serve a live HTTP 404 from the provider's edge with a service-specific message in the body. Some resolve and serve a generic error that means nothing in particular.

Two cautions attach to this step. A wildcard record in your zone destroys the NXDOMAIN signal entirely: if *.example.com answers, then every name answers, and "does it resolve" tells you nothing. And the widely circulated catalogue of provider error strings (can-i-take-over-xyz, which lists strings such as "The specified bucket does not exist" for S3 and "There isn't a GitHub Pages site here." for GitHub Pages) is a community project, not a vendor reference, and it says so itself.

"The authors of this document take no responsibility for correctness. This project is merely here to help guide security researchers towards determining whether something is vulnerable or not, but does not guarantee accuracy."
can-i-take-over-xyz, community project, GitHub

Treat it as low-confidence corroboration. Provider behaviour changes, entries go stale, and the list carries a mix of "vulnerable", "edge case" and "not vulnerable" verdicts that were true on the day someone tested them. It is a hint. Your console is the evidence.

Question three: does the provider require domain verification? This is the question that decides your priority order, and most published triage advice does not ask it at all.

Verification-gated providers are a different risk class

OWASP catalogues the test as WSTG-CONF-10 in the Web Security Testing Guide, and states two preconditions, not one: a DNS record pointing at a non-existent resource and a provider that fails to verify subdomain ownership. Both, together. Miss the second and every dangling record looks equally urgent, which is a good way to spend a fortnight on the wrong twelve records.

Microsoft states the effect of verification more precisely than anyone. Azure App Service supports a TXT record at asuid.{subdomain} carrying a domain verification ID.

"When such a TXT record exists, no other Azure subscription can validate the custom domain or take it over."
Prevent dangling DNS entries and avoid subdomain takeover, Microsoft Learn, July 20, 2026

And the part worth carrying into a conversation with a manager:

"These records don't prevent someone from creating an Azure App Service instance with the same name that's in your CNAME entry. Without the ability to prove ownership of the domain name, bad actors can't receive traffic or control the content."
Prevent dangling DNS entries and avoid subdomain takeover, Microsoft Learn, July 20, 2026

The resource name can be re-created. Your traffic still cannot be received. Those are different facts and they belong in different rows of your tracker.

GitHub Pages works the same way, using a _github-pages-challenge-USERNAME or -ORGANIZATION TXT record.

"Verifying your domain stops other GitHub users from taking over your custom domain and using it to publish their own GitHub Pages site."
Verifying your custom domain for GitHub Pages, GitHub Docs

GitHub also names the lifecycle events that produce the dangling state, which is a useful checklist in its own right: takeovers "can happen when you delete your repository, when your billing plan is downgraded, or after any other change which unlinks the custom domain or disables GitHub Pages while the domain remains configured for GitHub Pages and is not verified." A downgrade. Not a deletion, not an incident, not an attack. A billing change.

Google Cloud Storage applies the same gate to domain-named buckets: "To create a bucket that uses a domain name, you must establish that you are authorized to use the domain name." Verification runs through Search Console, and a verified domain owner supersedes site-level owners for buckets on all subdomains.

Contrast that with a flat namespace. AWS notes that buckets already created in the S3 global namespace cannot be migrated to an account regional namespace, and that those names remain globally unique and claimable by anyone if the bucket is deleted. No proof of domain ownership is involved anywhere in that sentence. That is your tier one.

The priority order writes itself:

TIER 1 flat, globally claimable namespace, no domain verification e.g. legacy S3 bucket names in the global namespace -> remediate first TIER 2 partial or platform-specific protections; behaviour varies by service -> verify in the provider console, do not guess TIER 3 provider requires proof of domain ownership before a custom domain attaches e.g. Azure App Service with asuid TXT, GitHub Pages with the challenge TXT, Google Cloud Storage domain-named buckets -> still remove the stale record; lower urgency, and say so in the report

Tier 3 records still get cleaned up. They are hygiene with a deadline rather than an incident with a clock, and being able to explain that difference is what stops a dangling-DNS review from turning into a fire drill.

Order of operations, when you decommission

Three independent first-party sources give the same sequence, which is unusual enough to be worth stating.

AWS's security blog is explicit that the DNS record comes out first: delete the CNAME that points at the FQDN of the resource you plan to deprovision, wait for the TTL to expire, and only then delete the resource. Deleting the resource first leaves cached CNAME entries still directing traffic at a name someone else can now claim. CloudFront's own documentation gives the same instruction for removing an alternate domain name:

"To start, route internet traffic for your domain to another resource that isn't your CloudFront distribution, such as an Elastic Load Balancing load balancer. Or you can delete the DNS record that's routing traffic to CloudFront."
Remove an alternate domain name, Amazon CloudFront Developer Guide

OWASP's cheat sheet adds one step at the front: put a redirect or maintenance page at the subdomain, then update or remove the DNS record, then allow at least the TTL to elapse, and only then decommission the cloud resource. For records already in the dangling state, WSTG-CONF-10 states the remediation in one line: "To mitigate the risk of subdomain takeover, the vulnerable DNS resource record(s) should be removed from the DNS zone. Continuous monitoring and periodic checks are recommended as best practice." Microsoft's remediation list opens the same way, with removal of CNAME records pointing at FQDNs of resources no longer provisioned. Our companion piece on public zone disclosure quotes that line and Microsoft's rebuttal of the belief that a TLS certificate protects you from a takeover; both are worth reading before you argue priority with anyone.

Two structural fixes are worth knowing about, and both have limits Microsoft states itself.

Alias records. "Azure DNS alias records can prevent dangling references by coupling the lifecycle of a DNS record with an Azure resource." Delete the underlying resource and "the DNS alias record becomes an empty record set." The lifecycle problem is solved by construction rather than by discipline. The catch is coverage: the supported set is currently four services, namely Azure Front Door, Traffic Manager profiles, Azure CDN endpoints and public IPs. Microsoft describes the list as currently limited. A partial structural fix is still a structural fix; it is not a programme.

Name reservations. When a classic cloud service resource is deleted, Azure reserves the DNS name for a period during which only subscriptions in the original Microsoft Entra tenant can reuse it. Microsoft is clear about what happens next: "After the reservation expires, any Azure subscription can claim the DNS name." A reservation window buys you time. It does not close the door.

One adjacent check, related but not the same thing. Route 53 documents "dangling delegation records": NS records in a parent zone pointing at name servers for a hosted zone that no longer exists. AWS protects against exactly one of the five scenarios it describes, and says so: "there are other dangling delegation record risks, which Route 53 can't protect against, as detailed in scenarios 2 through 5 in the following examples. To protect yourself against this broader set of risks, make sure the parent NS records match the delegation set for the Route 53 hosted zone." Different failure mode, different record type, same audit cadence. Keep it on the list; do not merge it with the CNAME work.

While you are in the zone, the stale TXT records that accumulate around vendor onboarding are worth a separate pass. They are a different and much smaller problem: a leftover verification token is inert information disclosure, not a routable weakness. We walked through what those tokens give away in From TXT Record to Tenant ID and how to read them in TXT Records — What They Are and How to Look Them Up. Do not let a tidy-up of inert tokens be recorded as remediation of a dangling CNAME.

What the measurements actually say

This topic attracts large numbers from vendor marketing. Most of them arrive without a population, a date or a method, and none of them are here for that reason. Two peer-reviewed measurements are worth quoting, with their scope attached.

Squarcina, Tempesta, Veronese, Calzavara and Maffei studied related-domain attackers (an attacker who controls a sibling subdomain, which subdomain takeover is one route to) across the top 50,000 domains of the Tranco list, published at USENIX Security '21.

"By building on this framework, we report on a large-scale security measurement on the top 50k domains from the Tranco list that led to the discovery of vulnerabilities in 887 sites, where we quantified the threats posed by related-domain attackers to popular web applications."
Can I Take Your Subdomain? Exploring Related-Domain Attacks in the Modern Web, Squarcina et al., author preprint, December 2020 (USENIX Security '21)

887 sites out of 50,000. Not a majority. Not nothing.

The second is Frieß, Gattermayer, Gelernter, Schulmann and Waidner, presented at USENIX NSDI '24, which reported the first confirmation of real-world cloud resource hijacking rather than demonstrated feasibility. The author preprint reports 20,904 instances of hijacked resources on popular cloud platforms, with roughly one in three persisting for more than 65 days. That persistence figure is the one that should shape your remediation SLA: these are not transient conditions that heal on their own.

The same study reports that roughly 75 percent of the observed abuse was blackhat SEO rather than malware distribution. That is a real cost — brand damage, search reputation, a legitimate-looking hostname serving somebody else's content — and it is not the ransomware story this topic usually gets told as. Remediate because the outcome is bad, not because someone said the word breach.

For a standards-track reference to hand to an auditor, NIST SP 800-81 Rev. 3, Secure Domain Name System (DNS) Deployment Guide was published in March 2026 by Scott Rose, Cricket Liu and Ross Gibson. It is the first revision since 2013, and it covers DNS threats to enterprise deployments.

The limits, including ours

Say these out loud before you present findings, because someone will ask.

A CNAME inventory is an inventory. It is not a vulnerability list, and converting one into the other requires the ownership check and the provider-verification question, both of which happen outside DNS.

No single test works across providers. NXDOMAIN, a live edge 404 with a service-specific body, and a generic error all occur, and a wildcard in your zone flattens the first signal completely.

Fingerprint lists are community-maintained and disclaim their own accuracy. Platform behaviour also keeps moving: CloudFront validates DNS when an alternate domain name is removed, Route 53 holds name servers in exactly one recreation scenario, and AWS's newer account regional namespace for S3 is not the default and cannot absorb existing global-namespace buckets. Research conclusions from 2020 do not apply uniformly in 2026.

And ours. DNSai gives you a CNAME inventory: the subdomains that currently publish a CNAME, the target, the chain depth up to 10 hops, and a bracketed IP address when the chain terminates in an A record. It never contacts a CNAME target over HTTP, never matches a provider error fingerprint, and never checks whether a target is claimed or claimable. It does not detect subdomain takeover, and there is no setting that makes it do so. The list is capped at 100 records and 45 seconds and seeded from public certificate logs, so it is a cross-check, not a census. Your zone export is the census.

The uncomfortable part of this whole exercise is that nothing in it is a detection. It is counting. Microsoft tells you to reconcile against what you own, AWS tells you to reconcile against what is in the account, OWASP tells you to keep the mapping documented, and MITRE tells you plainly that preventive controls will not cover the behaviour because it happens somewhere you cannot see.

Which leaves the boring answer. Export the zone. Group the targets. Open the consoles. Do it on a schedule, because the records that will hurt you are the ones created by a team that has since reorganised, pointing at a service that has since been cancelled, in an account nobody has logged into since the migration.

The record will keep answering. It has no idea.

Sources

  1. RFC 1034: Domain Names — Concepts and Facilities, Section 3.6.2 (Aliases and canonical names) — IETF / RFC Editor, November 1987. rfc-editor.org
  2. RFC 1035: Domain Names — Implementation and Specification, Sections 3.2.2 and 3.3.1 — IETF / RFC Editor, November 1987. rfc-editor.org
  3. RFC 5936: DNS Zone Transfer Protocol (AXFR), Section 5 (Authorization) — IETF / RFC Editor, June 2010. rfc-editor.org
  4. RFC 6962: Certificate Transparency, Section 3 — IETF / RFC Editor, June 2013. rfc-editor.org
  5. Compromise Infrastructure: Domains, Sub-technique T1584.001 (Resource Development, TA0042) — MITRE ATT&CK, v1.4, last modified May 12, 2026. attack.mitre.org
  6. Prevent dangling DNS entries and avoid subdomain takeover — Microsoft Learn (Azure security fundamentals), July 20, 2026. learn.microsoft.com
  7. Threat tactic spotlight: Subdomain takeover (Matt Gurr, Ariam Michael, Geoff Sweet, Luis Pastor) — AWS Security Blog, June 16, 2026. aws.amazon.com
  8. Remove an alternate domain name — Amazon CloudFront Developer Guide, AWS. docs.aws.amazon.com
  9. Protection from dangling delegation records in Route 53 — Amazon Route 53 Developer Guide, AWS. docs.aws.amazon.com
  10. Verifying your custom domain for GitHub Pages — GitHub Docs. docs.github.com
  11. Domain-named bucket verification | Cloud Storage — Google Cloud. docs.cloud.google.com
  12. Hosting a static website using HTTP | Cloud Storage — Google Cloud. cloud.google.com
  13. Test for Subdomain Takeover (WSTG-CONF-10) — OWASP Foundation, Web Security Testing Guide. owasp.org
  14. Subdomain Takeover Prevention Cheat Sheet — OWASP Cheat Sheet Series. cheatsheetseries.owasp.org
  15. Can I Take Your Subdomain? Exploring Related-Domain Attacks in the Modern Web (Squarcina, Tempesta, Veronese, Calzavara, Maffei) — USENIX Security '21; open author preprint, December 3, 2020. arxiv.org
  16. Cloudy with a Chance of Cyberattacks: Dangling Resources Abuse on Cloud Platforms (Frieß, Gattermayer, Gelernter, Schulmann, Waidner) — USENIX NSDI '24; open author preprint, March 28, 2024. arxiv.org
  17. USENIX NSDI '24 presentation page for the above — USENIX, April 2024. usenix.org
  18. SP 800-81 Rev. 3, Secure Domain Name System (DNS) Deployment Guide (Scott Rose, Cricket Liu, Ross Gibson) — NIST / CSRC, March 2026, DOI 10.6028/NIST.SP.800-81r3. csrc.nist.gov
  19. can-i-take-over-xyz — a list of services and how to claim (sub)domains with dangling DNS records — EdOverflow, community project on GitHub. Cited only for the existence and self-declared accuracy limits of a community fingerprint list. github.com

Share this article