It started with a boring task. Quarterly DNS audit. Coffee, a zone file, and a vague sense that everything was fine.

It was not fine.

Halfway down the export I hit a CNAME — a customer-facing subdomain — pointing at a cloud host we’d decommissioned back in the winter. The instance was gone. The DNS record had never gotten the memo.

I sat there for a second. That subdomain still resolved. It still answered. It just answered nothing — a hosting account that no longer existed, on infrastructure we’d long since stopped paying for.

That’s not a typo. That’s a loaded gun pointed at your own brand.

The investigation

A dangling DNS record is a pointer with no backing store. The record says “this name lives over there.” But “over there” got freed months ago — the VM was destroyed, the cloud bucket released, the hosting account closed.

The danger isn’t that it’s broken. The danger is that the resource is now available for anyone to claim.

I pulled the full zone and started checking targets one by one. Does the A record’s IP still belong to us? Is the CNAME target a hostname we still control? Or is it a now-orphaned cloud resource sitting in a provider’s free pool, waiting for the next person to grab it?

        Your DNS                      The Internet
   ┌──────────────────┐         ┌────────────────────────┐
   │ app.example.com  │         │  cloud host (DELETED)   │
   │  CNAME ──────────┼────────▶│  account closed, freed  │
   └──────────────────┘         │  ▒▒▒ up for grabs ▒▒▒  │
                                └───────────┬────────────┘
                                            │  attacker
                                            ▼  re-claims it
                                ┌────────────────────────┐
                                │  serves THEIR content   │
                                │  on YOUR subdomain      │
                                └────────────────────────┘

The “aha”

Here’s the part that turns a stale record into a breach.

If an attacker registers that freed cloud resource — same provider, same dangling target — the provider hands them the keys. Now your subdomain serves their content. And because it’s your subdomain, the blast radius is ugly:

  • Pixel-perfect phishing on a domain your users already trust.
  • Cookies scoped to *.example.com get harvested — including session cookies from your real apps.
  • A free, fully valid TLS certificate, because the takeover host can pass the domain-control check for a name you literally pointed at it.

No CVE. No exploit chain. Just a DNS record that outlived its server.

app.example.comCNAME >freed hostup for grabsattackerre-claims itvalid TLS & your name = phishing on brand
A deleted host gets re-claimed — and your trusted subdomain serves someone else's payload.

The fix

First, inventory everything. Pull the whole zone, not just the records you remember.

# Dump every A / AAAA / CNAME in the zone
dig @ns1.example.com example.com AXFR \
  | awk '$4 ~ /^(A|AAAA|CNAME)$/ {print $1, $4, $5}'

Then resolve each one and check whether the target still answers — and whether it’s still yours.

while read -r name type target; do
  echo "=== $name ($type) -> $target"
  dig +short "$name"
  curl -sS -o /dev/null -w "  http=%{http_code} ip=%{remote_ip}\n" \
    --max-time 8 "https://$name" || echo "  DEAD / no response"
done < zone-records.txt

For the dangling ones, the rule is simple: if you don’t control the target, the record dies or gets repointed.

# Delete the stale record (RFC 2136 dynamic update)
nsupdate -k /etc/dns/update.key <<'EOF'
server ns1.example.com
zone example.com
update delete app.example.com. CNAME
send
EOF

Repoint anything still in use at infrastructure you own — a host behind your own reverse proxy, not a third-party resource you might let lapse again.

Finally, make it a standing job. A nightly check that flags any record whose target stops resolving or stops belonging to you.

# cron: nightly dangling-DNS sweep, alert on dead targets
0 4 * * *  /opt/dns/dangle-check.sh && \
  curl -fsS https://hc-ping.test/dns-sweep

Why it happened

DNS outlives servers. Always.

When you spin a box down, you delete the box. You raise the ticket, you confirm it’s gone, you move on. The DNS record — living in a different system, owned by a different runbook — just sits there pointing at a ghost. Nobody’s job ends with “and remove the CNAME.”

Multiply that by a few years of “temporary” subdomains and deprovisioned cloud accounts, and you’ve got a quiet pile of doors with no locks.

Takeaways

  • Inventory every record. You can’t audit a zone you’ve only half-remembered. Pull the whole thing.
  • Verify the target, not just the name. A record that resolves isn’t safe — confirm the thing it points at is still alive and still yours.
  • Prune the moment a server dies. Decommissioning a host isn’t done until its DNS is gone too. Bake it into the runbook.
  • Prefer targets you control. Point subdomains at your own infrastructure, not third-party resources you might forget to renew.
  • Monitor continuously. Dangling DNS is created by routine. Catch it with routine — a nightly sweep beats a quarterly surprise.