Subdomain takeover: the DNS security risk in abandoned records
作者:Seaworthy · 2026年6月19日
Photo by Kevin Ache on Unsplash
The mechanism nobody thinks to clean up
When you connect a subdomain to a third-party service, you add a CNAME record to your DNS. That record says "requests to staging.yourdomain.com should go to your-app.herokuapp.com". Simple enough. But DNS records outlive the services they point to. The app gets deleted; the CNAME stays.
This is a dangling CNAME. It is one of the most underrated attack vectors in web security.
Here is what happens when an attacker finds one. They enumerate your subdomains using certificate transparency logs or a wordlist-based scan. They find staging.yourdomain.com. They resolve it, follow the CNAME, and land on an unclaimed Heroku app name. So they register it. Now they serve whatever they want from your subdomain. The SSL certificate may even be re-issued for it, depending on the CA and the platform.
Why this is worse than it looks
The attacker is not just hosting a phishing page. They inherit the trust of your domain.
Cookies set with the Domain=.yourdomain.com attribute are sent to all subdomains, including the one the attacker just claimed. Any cookie scoped broadly to your domain is now readable by them. Session tokens, auth credentials from legacy integrations, tracking identifiers: all of it flows to that subdomain.
There is also the same-origin policy to consider. A script running on staging.yourdomain.com can set cookies that will be sent to app.yourdomain.com. That is a cross-subdomain cookie injection attack, and it bypasses most of what developers consider "secure" cookie configuration. Setting HttpOnly does not save you here. The cookie is sent to the attacker's origin on the poisoned subdomain, and any new cookies they set on that domain are forwarded to your legitimate app.
Which services get you
GitHub Pages is the canonical example. You create a CNAME file in a repo, point your subdomain at username.github.io, then delete or rename the repo. The subdomain is now ownable by anyone. Detectify has tracked hundreds of real-world takeovers using this exact path.
AWS S3 buckets are another well-worn route. Buckets have globally unique names. Point a CNAME at my-old-site.s3-website-eu-west-1.amazonaws.com, delete the bucket, and that name becomes available for anyone to register in their own account.
Fastly, Azure Web Apps, Zendesk, Intercom, Shopify, and a dozen other platforms have all been exploited this way. The vulnerability is not specific to any one service. It lives in the gap between "we stopped using this" and "we never cleaned up DNS".
Detecting dangling CNAMEs
The basic check: resolve the CNAME, then see if the target responds as a claimed, active resource. If you get a service-level 404 indicating the resource does not exist on that platform, you have a problem.
# Resolve the CNAME target for a subdomain
TARGET=$(dig +short CNAME staging.yourdomain.com)
echo "CNAME target: $TARGET"
# Check what HTTP status the target returns
curl -s -o /dev/null -w "%{http_code}" "https://${TARGET%?}"
Heroku returns a 404 with a specific error body for unclaimed apps. GitHub Pages returns There isn't a GitHub Pages site here. Each platform has a fingerprint. The community-maintained list at can-i-take-over-xyz documents these per service, including which ones are confirmed exploitable and which require extra steps.
Running this kind of check manually across all your subdomains is tedious. Automating it means keeping that fingerprint list current, which is its own ongoing maintenance burden.
Fixing it
The immediate fix: remove CNAME records for services you no longer use. Pull your DNS records and compare them against your active services. If you cannot tell whether something is still in use, treat it as abandoned.
You can audit your Cloudflare zone records programmatically rather than hunting through the dashboard:
# List all CNAME records in a Cloudflare zone
curl -s "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/dns_records?type=CNAME" \
-H "Authorization: Bearer $CF_TOKEN" | \
jq '.result[] | {name: .name, content: .content}'
Most DNS providers expose a similar API. The output gives you a flat list you can cross-reference against your current infrastructure.
For new deployments, build decommissioning into your process. When you spin down a service, DNS cleanup should sit on the same checklist as revoking API keys and closing the billing account. It is easy to forget when you are shutting things down in a hurry.
If you want to keep the subdomain active but retire the underlying service, point it at a stub you control. A redirect or placeholder served from your own infrastructure is far better than leaving an unclaimed external resource dangling there.
Make it part of your security hygiene
Certificate transparency logs are public. Attackers use them to enumerate your subdomains systematically before you even know they are looking. You should be doing the same audit yourself first.
The scale problem is real. DNS records accumulate. Projects get handed off. Teams grow and contractors rotate. Nobody knows who set up that CNAME four years ago for a campaign microsite that no longer exists. This is not a theoretical risk you can defer until you hire a security team; it is the kind of thing that gets exploited against small projects precisely because they are assumed not to have defences in place.
Treat abandoned DNS records the same way you treat abandoned API keys: as a live vulnerability until proven otherwise. A dormant CNAME pointing at an unclaimed resource is not neutral. It is an open door.
Seaworthy checks for dangling CNAME records pointing at known third-party platforms as part of its DNS and configuration analysis.
本文由 AI 生成,总结了公开可用的来源。
Seaworthy 会扫描你的代码仓库,发现类似本文提到的各种问题。
安全漏洞、泄露的密钥和配置错误——在部署前捕获。免费运行,无需账户。