Subdomain Takeover: How Dangling DNS Gets Hijacked

Subdomain takeover explained: how dangling CNAME, NS and MX records get claimed by attackers, and the exact commands to check whether your domain is exposed.

Share
Subdomain Takeover: How Dangling DNS Gets Hijacked

Subdomain takeover is one of the oldest tricks in the book, and it still works because the root cause is organizational rather than technical. You point a subdomain at a third-party service, the service goes away, and nobody deletes the DNS record that referenced it. That leftover record is a dangling DNS entry, and anyone who can claim the abandoned resource inherits your subdomain.

The technique got wide attention in 2024 when Guardio Labs documented SubdoMailing, a spam operation that ran on thousands of hijacked brand subdomains. That campaign is over, but the mechanism behind it was never campaign-specific. It turns up in bug bounty reports every week, and in 2025 the Hazy Hawk group used the same dangling CNAME trick against government agencies, universities and large firms. If you run a domain, the useful question is not what happened in 2024 but whether you are exposed right now.

What a subdomain takeover actually is

Two conditions have to line up. First, a DNS record on your domain points at a resource you no longer control, usually because the resource was deleted but the record was left behind. Second, the provider that hosted the resource lets a new customer claim the same name. When both are true, an attacker registers the freed name and controls what loads on your subdomain.

The classic shape is a CNAME record. A marketing team points promo.example.com at an app on Heroku, the campaign ends, the app is deleted, and the CNAME stays. The record now resolves to a hostname that answers "No such app". Anyone can create a Heroku app with that name and serve whatever they like on promo.example.com.

What makes this worse than a defaced page is everything the subdomain inherits. It sits inside your cookie scope, your TLS story and your reputation. A page served there is treated as yours by browsers, mail filters and search engines, which is exactly why attackers want it.

The records that get left dangling

CNAMEs are the most common vector, but they are not the only record type that can be orphaned. The ones most often left behind when a service is decommissioned are these:

Record typeHow it goes danglingWhat an attacker gets
CNAMEThe subdomain points at a third-party hostname whose resource was deletedControl of the subdomain and anything served from it
APoints at a static IP that was released back to the provider's poolThe IP, and therefore the hostname, if they obtain it
NSThe subdomain is delegated to a DNS provider whose account was closedThe whole delegated zone, and every record under it
MXPoints at a mail service that no longer existsInbound mail for the subdomain, including password resets

NS is the one to worry about most. A dangling CNAME costs you a single subdomain. A dangling NS delegation can hand over every record beneath it, which is a much larger blast radius. MX is quieter but enables a specific attack: with control of inbound mail for a subdomain, an attacker can pass email-based domain validation and get a real TLS certificate issued for it.

Which services are the usual suspects

Takeover is possible whenever a provider lets a new account claim a name that was previously in use. That covers most static hosting and app platforms. The table below lists the common ones, with the response that tells you the resource behind the record is gone.

ServiceCNAME target looks likeFingerprint of an unclaimed resource
AWS S3 (website hosting)*.s3.amazonaws.com, *.s3-website-*.amazonaws.comNoSuchBucket or "The specified bucket does not exist"
AWS Elastic Beanstalk*.elasticbeanstalk.comDefault environment error page
Azure App Service*.azurewebsites.netAzure default 404 for a missing app
Azure Traffic Manager*.trafficmanager.netProfile not found
GitHub Pages*.github.io"There isn't a GitHub Pages site here."
Heroku*.herokuapp.com"No such app"
Shopifyshops.myshopify.com"Sorry, this shop is currently unavailable."
Netlify*.netlify.appProvider 404 for an unclaimed site
Fastly*.fastly.netProvider 404
Zendesk*.zendesk.comPortal not found

There are conditional cases too. A CloudFront distribution that was deleted while the CNAME remains can be reclaimed. A Google Cloud Storage bucket name is globally unique and reclaimable after deletion. Both belong on your audit list. Check current provider behaviour against can-i-take-over-xyz before you assume a service is safe, because these policies change.

Why it matters beyond a defaced page

The damage is not just someone else's content sitting on your domain. A hijacked subdomain can:

  • Read cookies scoped to the parent domain. A cookie set for .example.com is sent to an attacker-controlled subdomain.
  • Bypass a Content Security Policy that trusts wildcard subdomains such as *.example.com.
  • Host convincing phishing pages on a domain your users already trust, and pass email authentication checks while doing it. This is the link between dangling DNS and SPF, DKIM and DMARC.
  • Satisfy OAuth or SSO redirect allowlists that treat the subdomain as yours.
  • Obtain a valid TLS certificate for the subdomain through HTTP or email domain validation.
  • Receive mail addressed to the subdomain if an MX record is involved.

For an organization the practical result is lost trust, a certificate revocation exercise, and a hunt for every other record the same process gap left behind. That last part is the one people underestimate. If one record was left dangling, others usually were too, because the missing step is a process rather than a single mistake.

How to check whether your own domain is exposed

This is the part worth doing today. The check has three steps: enumerate your subdomains, find the ones that resolve to a third party, and look for a response that says the resource behind them is gone. If you already keep an attack surface inventory from external recon, this fits alongside it.

Step 1: enumerate and resolve

# 1. Enumerate subdomains (passive sources plus certificate transparency)
subfinder -d example.com -all -silent -o subs.txt

# 2. Resolve them and keep the ones that point somewhere via CNAME
dnsx -l subs.txt -cname -resp -silent -o cnames.txt

Step 2 is the one people skip. A record that returns NXDOMAIN at the provider is a candidate, but so is one that returns a provider error page. Both mean the resource is gone.

Step 2: probe for fingerprints

# 3. Find which of them actually answer over HTTP or HTTPS
httpx -l subs.txt -silent -o live.txt

# 4. Look for takeover fingerprints in the responses
nuclei -l live.txt -tags takeover

If you want a single tool rather than a pipeline, dnsReaper walks a domain or a whole zone and matches it against more than 50 provider signatures. It can also pull your records straight from a DNS provider so you audit live configuration instead of a stale export.

Step 3: run a dedicated scanner

# Scan a single domain
docker run --rm punksecurity/dnsreaper single --domain example.com

# Or scan a list of subdomains from a file
docker run --rm -v "$(pwd):/etc/dnsreaper" punksecurity/dnsreaper \
  file --filename /etc/dnsreaper/subs.txt

# Or pull your records straight from the DNS provider (AWS Route 53 shown)
docker run --rm punksecurity/dnsreaper aws \
  --aws-access-key-id "$AWS_ACCESS_KEY_ID" \
  --aws-access-key-secret "$AWS_SECRET_ACCESS_KEY"

For a single subdomain you can do the whole check by hand. Follow the CNAME chain, then read what the target returns:

dig +short CNAME promo.example.com
curl -sS -D - https://promo.example.com/ -o /dev/null | head -n 1

Then match the body against the fingerprint table above. If you see "No such app", "There isn't a GitHub Pages site here", or an S3 NoSuchBucket, the record is dangling and someone else can claim it. If you want to sweep your own domain names for lookalikes and expired assets as well, the same DNS recon habits used for typosquatting discovery apply here.

Preventing the next one

The fix is an ordering rule, not a tool. Most of the exposure disappears if decommissioning runs in the right sequence:

  1. Delete the DNS record first, then wait for the TTL to expire.
  2. Only after that, deprovision the cloud resource.
  3. Check that the record no longer resolves before you close the ticket.

That order closes the window entirely. Doing it the other way round, which is the common mistake, leaves the record pointing at nothing for as long as it takes someone to notice.

Beyond the ordering rule:

  • Keep an inventory of every DNS record and what it points at, including who owns the third-party service. You cannot clean up records you do not know exist.
  • Run a takeover scan on a schedule, ideally in CI when a new DNS record is proposed, so a dangling record is caught before it goes live.
  • Watch Certificate Transparency logs, for example Cert Spotter, for certificates issued for your subdomains that you did not request.
  • Verify domain ownership at the provider wherever it is offered, so a name cannot be claimed by a different account.
  • Remove stale NS delegations, not just stale CNAMEs. A forgotten delegation is the highest-impact version of this problem.
  • Review zones inherited from acquisitions, where the original owners are often unavailable and the inventory is thin.

The broader reference for this is the OWASP Subdomain Takeover Prevention Cheat Sheet, which covers the same ground with a provider-by-provider table. Microsoft documents the Azure side of it in Prevent dangling DNS entries and avoid subdomain takeover, and AWS has its own walkthrough in Threat tactic spotlight: Subdomain takeover.

If a record has already been taken over

Assume the worst case, because the subdomain may have been serving phishing content for a while:

  1. Remove the DNS record immediately. That is the fastest mitigation and it breaks the link to the attacker's resource.
  2. Check Certificate Transparency logs and request revocation of any certificate issued for the subdomain during the takeover window.
  3. Work out what the subdomain could have touched: cookies scoped to the parent domain, OAuth or SSO allowlists, and any mail that arrived while an MX record was dangling.
  4. Notify users if there is evidence that credentials were phished or sessions were intercepted.
  5. Scan every other zone you own. The same process gap that produced one dangling record usually produced others.

Historical examples worth knowing

The technique is not new. Detectify described the first widely reported wave in a 2014 writeup covering Heroku, GitHub and Desk. Guardio Labs put it back on the map in 2024 with SubdoMailing, showing that a dangling CNAME plus a forgotten SPF entry was enough to send mail that passed authentication. The following year, Infoblox documented the Hazy Hawk actor using dangling CNAMEs at abandoned cloud resources to run scams and malware through trusted subdomains.

Different years, different motives, same root cause. Someone deleted a resource and left the record behind. The check above takes minutes, and it is the same check that would have caught every one of those cases.

## Convertkit Newsletter