Dangling CNAME Records Are A Subdomain Takeover Waiting To Happen.
A CNAME pointing at a released service name lets a stranger serve content on your client’s subdomain. Two lookups find them across a portfolio.
Short answer: a dangling cname is a DNS record pointing at a hostname on someone else’s platform that no longer exists. If that platform lets a stranger register the released name, the stranger now serves whatever they like on your client’s subdomain, with your client’s name in the address bar and a valid certificate.
Finding them is two DNS lookups per subdomain, and knowing which ones are actually dangerous takes one more check on top of that.
The dangling CNAME check, in two lookups

correctly. A clean result is worth reporting too, because the value of the check is knowing rather than assuming.*
The logic is deliberately simple. Does this name have a CNAME? Does the thing it points at resolve to anything? A yes followed by a no is the finding.
How one is created

one. Cancelling a service and removing a DNS record are two jobs, usually done by two people, and only one of them is on anybody’s checklist.*
| # | What happened | What was left behind |
|---|---|---|
| 1 | a subdomain is pointed at a hosted service | staging.client.com CNAME app.someplatform.io |
| 2 | the project ends, the account is closed | the platform releases the name back into its pool |
| 3 | nobody removes the DNS record | the CNAME still points there |
| 4 | someone else registers that name | they now serve content on your client’s subdomain |
It is the same shape as a plugin that was pulled from the directory: the thing that changed happened somewhere else, on somebody else’s system, and your site was never told.
Every dangling record I have seen was the tidy half of a job done well. The migration succeeded. The staging site was retired properly. The campaign ended on schedule. The DNS entry stayed.
Whether it is actually exploitable
This is where I would push back on tools that report every unresolving CNAME as critical.

stale record pointing at your own retired server is untidy. One pointing at a released name on a shared platform is a live issue.*
| Service type | Reclaimable? | What that means |
|---|---|---|
| static hosting and preview platforms | usually | project names return to a shared pool |
| cloud storage buckets | usually | bucket names are globally unique, released on delete |
| marketing / landing-page tools | often | subdomains on a shared platform, freed when an account closes |
| helpdesk and status pages | sometimes | depends whether the vendor reserves retired names |
| your own server by hostname | no | the name is yours, the record is stale, not dangerous |
So the finding is “this record points at nothing, and the target is on a platform where names are reclaimable.” That is a sentence you can send a client. “Critical vulnerability” is not, until you have checked the second half.
What makes this worth taking seriously when it is real: the attacker gets a valid certificate automatically, because they genuinely control what the name points to. There is no browser warning. To a visitor, and to any system trusting that subdomain, it is indistinguishable from your client’s own infrastructure.
Re-checking our own record, and what an unclaimed target actually looks like
I re-ran the exact lookup this post opens with against our own domains before expanding it, rather than reuse a screenshot from months ago without confirming it still holds.
dig +short CNAME docs.protuno.com
dig +short A 719cef8bddc9c3f9.vercel-dns-017.com
curl -s -o /dev/null -w '%{http_code}\n' https://docs.protuno.com/
719cef8bddc9c3f9.vercel-dns-017.com.
216.150.1.1
200
Still resolves, still live. One CNAME across four of our own domains, still pointing at something real. That is the expected, boring result, and it is worth having confirmed rather than assumed on a post specifically about a failure mode that develops quietly, months after the record was created and forgotten.
What I had not checked before is what the “unclaimed” side of this actually looks like from the outside, on a platform where names are genuinely reclaimable, so I requested a handful of subdomains I picked specifically because nobody could plausibly have registered them:
curl -s -o /dev/null -w '%{http_code}\n' "https://this-project-should-not-exist-928471.vercel.app"
curl -s "https://this-project-should-not-exist-928471.vercel.app"
404
DEPLOYMENT_NOT_FOUND
No hijack attempted, nothing registered, only a request against an obviously unused name on a public platform to see how it answers. The same request against three other common targets produced three differently worded but equally clear “nothing is here” responses:
| Platform | Unclaimed-name response |
|---|---|
| Vercel | 404, DEPLOYMENT_NOT_FOUND |
| GitHub Pages | 404, HTML page titled “Site not found · GitHub Pages” |
| Netlify | 404, Not Found - Request ID: ... |
| Heroku | 404, generic platform error page |
| AWS S3 (unclaimed bucket) | 404, XML body: |
S3’s version, checked the same way, is the most explicit of the five, naming the exact failure in the response body itself rather than requiring the wording to be interpreted:
curl -s "https://this-bucket-should-not-exist-928471-posi.s3.amazonaws.com"
<Error><Code>NoSuchBucket</Code><Message>The specified bucket does not exist</Message>
<BucketName>this-bucket-should-not-exist-928471-posi</BucketName>...</Error>
NoSuchBucket on a CNAME target that used to point at an S3 bucket is about as unambiguous a “this name is claimable” signal as this check produces. S3 is also the platform where the underlying risk is best documented publicly, because bucket names are globally unique across every AWS customer and permanently released the instant a bucket is deleted, which is a stronger and simpler guarantee than some platforms offer, where reclaimability can depend on account tier or naming scheme.
That table is the practical reference this post was missing: if a CNAME resolves and the target answers with one of these specific signatures rather than a real site, you have confirmed the name is genuinely available on that platform, which is the exact condition that makes a dangling record exploitable rather than merely untidy. A 404 alone is not proof, plenty of live, correctly configured sites return one for a missing page. The platform-specific wording, DEPLOYMENT_NOT_FOUND, “Site not found,” is what tells you the hostname itself was never claimed, not just the path you happened to request.
A wider wordlist, checked against our own domain
The scan this post opened with checked fifteen common subdomain names. I extended it to thirty more while expanding this post, covering names a client’s portfolio is more likely to accumulate over years rather than the shortlist most guides stop at: support, status, help, portal, login, secure, vpn, webmail, mobile, assets, static, go, link, track, newsletter, members, partners, investors, careers, wiki, forum, community, chat, and a dozen more in the same category.
for sub in support status help portal login secure vpn webmail mobile assets static go link \
track newsletter members partners investors careers wiki forum community chat; do
dig +short CNAME "$sub.protuno.com"
done
Nothing. Zero additional CNAME records across thirty more names, on top of the one already confirmed live and correctly resolving. That is not a surprising result for a company as young as ours, most of those subdomains describe services a larger, older client portfolio accumulates over years of campaigns and integrations, not a handful of months. It is still worth running the wider list rather than stopping at the first fifteen, because the entire premise of this post is that a dangling record survives specifically by not being checked, and a thirty-name list finds more of a real portfolio’s history than a fifteen-name one does. The list is free to extend. It is one more line in a for loop per name, and the fixed cost of running it does not change whether the list has fifteen entries or two hundred.
Fixing and preventing
The fix is to delete the record. There is no cleverer answer, and it takes seconds.
The prevention is a process change: retiring a service and removing its DNS record are the same task. Whoever closes the account removes the CNAME in the same sitting. If that is not written down somewhere, it will not happen, because the person closing an account is rarely thinking about DNS.
Then run the scan quarterly. Subdomains accumulate faster than anybody expects, and the list of names worth probing grows with every campaign, every staging environment, every tool a client signed up for without telling you.
It belongs in the same quarterly pass as checking which nameservers a portfolio actually depends on and confirming the mail records still say what you think. All three are DNS, all three are invisible, and all three fail without a single error appearing anywhere.
Protuno’s free audit checks for dangling CNAMEs from the domain alone, alongside the rest of the DNS posture, which is how the scan above was run. Straight with you as on every post here: Rook, the Security agent that would repeat this on a schedule, is built and named but not live yet.
Run the loop on the client whose site you migrated most recently. Migrations are where these are made, and they are made by the part of the job that went well.
Why “critical” is the wrong word for most of what this finds
Worth restating plainly, because it is the part of this post most likely to get lost between the scan results and the fix: the majority of what a dangling-CNAME scan turns up across a real portfolio is not exploitable. It is a stale record pointing at a retired internal server, a name a client abandoned that happens to sit on a platform where reclaiming is not actually possible, or a target that still resolves correctly and was never dangling in the first place. Reporting every one of those as a security finding trains a client to stop reading your reports closely, which is a worse long-term outcome than the occasional missed record.
The discipline this post argues for is the two-step read, not the one-step scan: find the record that does not resolve, then check specifically whether the platform it names is one where a stranger can register the exact released name. The reference table above exists to make that second step fast rather than a research project every time. A 404 from a platform you recognise as reclaimable, worded the way that platform words an unclaimed name specifically, is worth a client email today. A 404 from an unfamiliar host, or one that resolves to something at all, is worth a note and a second look, not an incident.
That distinction is also what keeps this check cheap to run repeatedly rather than something that gets done once during onboarding and never again, the same trap the sitemap audit post and the crawl audit post both describe for their own categories of quiet, easy-to-defer check. A scan that reports thirty false positives a quarter gets switched off. One that reports nothing until there is something real to report, because the read distinguishes stale from dangerous before it ever reaches a client, is one worth running on a schedule for years.
What a correctly-pointed CNAME actually looks like
Useful as a reference for the healthy case this post’s check is comparing against: a CNAME pointed at a host that still claims it, versus the released, unclaimed target a takeover needs.
Comments