Why subdomain takeover is easy to underestimate
Subdomain takeover sounds like a niche finding. It does not involve a fancy exploit or a complex payload. All I need is a DNS record that points to a service that no longer exists. The result can be severe, though, because a subdomain of a trusted domain can be used for phishing, cookie theft, and malware hosting. I did not take the bug seriously until I saw how much trust a single subdomain can carry.
This post is my personal study note on subdomain takeover. I am writing it because the detection process is mostly boring DNS and HTTP checks, but the interpretation requires care. A CNAME that points to a deleted project is not automatically a takeover. I need to verify that the service can be claimed by a third party and that the claim actually changes the content served on the subdomain.
How a takeover happens
The takeover condition starts with a DNS record. A subdomain has a CNAME record that points to an external service, such as GitHub Pages, Heroku, S3, Azure, Netlify, or a similar platform. The organization uses that service for a while and then deletes the project. The DNS record is not deleted. Now the CNAME still exists, but the destination is empty.
The empty destination may respond with an error page that says the project does not exist. That error page is the signal I am looking for. If the service allows anyone to register the same project name, I can create a project with that name and take control of the subdomain.
The severity depends on the parent domain. A subdomain on example.com inherits cookies, security scope, and user trust from the parent. If a user visits help.example.com and sees a login page, they may assume the page is official. That trust is exactly what makes takeover dangerous.
The first step: collect CNAME records
The detection process starts with a complete list of subdomains. I use the same passive sources that I use for reconnaissance: certificate transparency, DNS history, and search results. Once I have the list, I query the CNAME record for every subdomain. The CNAME tells me where the subdomain points.
I look for CNAME targets that belong to known takeover-prone platforms. The list includes GitHub Pages, Heroku, S3, Azure, Netlify, Shopify, and many others. Each platform has a specific error page when the resource does not exist. I keep a table of these error strings in my notes.
The CNAME alone is not enough. A CNAME to an external service can be completely healthy. I need to combine the DNS result with an HTTP request to the subdomain and look at the response. The error page is the second signal.
Checking the HTTP response
The HTTP response tells me whether the destination is alive. I send a request to the subdomain with a normal browser user agent and a couple of uncommon user agents. Some platforms serve different content based on the user agent. I record the status code, the body, and the redirect chain.
An error page that says "repository not found" is a strong signal for GitHub Pages. A page that says "no such bucket" is a strong signal for S3. A page that says "application not found" is a strong signal for Heroku. I do not rely on the exact wording alone, because platforms change their error pages. I compare the response with the documented behavior for the platform.
The redirect chain is also important. Some platforms redirect to a signup page or a generic error page. The redirect target can confirm that the resource is missing. If the response is a 200 with the platform's default page, the destination is probably still claimed by the original project.
Validating that the service can be claimed
The error page is only half of the story. I also need to know whether the service allows a third party to register the same name. I check the platform documentation and, when possible, create a test project on my own account.
The test project should use a name that is unlikely to conflict with anything real. I use a random suffix so that I do not accidentally claim a name that belongs to the target. The goal is to verify the platform behavior, not to interfere with the target.
Some platforms require a verification file before a custom domain can be used. Others allow the custom domain immediately. I check the requirements and adjust the proof of control accordingly. If the platform requires a file, I cannot take over the subdomain without also controlling the DNS or the original account. That changes the finding.
Proving control safely
The final validation is proof of control. I register the name on the external platform using an account that I control and that is separate from the target organization. I upload a unique proof file, such as a text file with a random string, and I confirm that the file is served on the affected subdomain.
The proof should be non-destructive. I do not replace the original content if there is any. I do not create a phishing page. I do not leave the proof in place after the test. I document the proof file, the response, and the time of the test, and then I remove the proof content.
The proof demonstrates that I can control the content served on the subdomain. That is the definition of a takeover. If I can only register the name but cannot serve content, the finding is different and should be reported as a risk rather than a confirmed takeover.
Why the takeover happens
The root cause is usually a decommissioning process that forgets DNS. An organization deletes a project, closes an account, or migrates a service to a new provider, but the old CNAME record remains. The record is invisible to most users, so nobody notices until a scanner finds it.
Another common cause is the use of test subdomains. A developer creates a subdomain for a demo, points it to a platform, and never removes it after the demo ends. The subdomain stays in DNS, and the platform eventually releases the resource name.
The business impact depends on the subdomain. A marketing page is less critical than a login portal. An internal tool is more sensitive than a static site. I assess the impact by looking at what the subdomain would normally be used for and how users might interact with it.
Reporting the finding
A takeover report should include the subdomain, the CNAME target, the platform, the error page, and the proof file. I include the exact DNS record and the HTTP response so that the developer can reproduce the finding. I also include the steps I took to prove control and the fact that I removed the proof afterward.
The report should explain the business impact. I describe what an attacker could do with the subdomain, such as hosting phishing pages, stealing cookies, or distributing malware. I also describe the scope of the impact, because a subdomain that is rarely visited is less urgent than one that is used for authentication.
I do not include the proof file content in the final report if it contains a value that could be used to claim the subdomain again. I redact the value and describe the response instead.
Preventing takeover
The best prevention is an inventory of DNS records. Every CNAME should have an owner and a purpose. When the underlying service is decommissioned, the DNS record should be deleted at the same time. This sounds simple, but it requires a process that links the service decommissioning to the DNS change.
Platform verification tokens are another control. Some platforms let an organization verify ownership of a domain by uploading a file. If the verification file is required, a third party cannot claim the domain without also controlling the original account. This reduces the takeover risk.
Periodic DNS audits can catch records that were forgotten. I recommend checking the CNAME targets against a list of known platforms and looking for error pages that indicate a missing resource. The audit should be automated enough to run regularly but reviewed by a person who can interpret the results.
DNS history
DNS history is a source of takeover candidates that I often forget. A subdomain that used to point to a platform may have changed its DNS record. The old record is still visible in the historical data, even if the current record is different.
I query the historical DNS records for every subdomain in the inventory. The query shows the CNAME targets that the subdomain used in the past. If the old target is now available, the subdomain may still be vulnerable.
The history also shows the age of the record. A record that has been pointing to a deleted service for years is a stronger candidate than a record that was changed yesterday. The age suggests that the organization is not monitoring the DNS.
The history is not a live finding. I still need to check the current DNS and the HTTP response. The history is a way to find the candidates that the current scan misses.
Email and TLS clues
The email configuration can reveal subdomains that are not in the web inventory. A mail server, an SPF record, or an MX record may reference a hostname that I have not seen. I parse the DNS records and add the hostnames to the list.
The TLS certificates are another source. I query the certificate transparency logs for the domain and look for hostnames that are not in the web inventory. The certificates are the same source that I use for reconnaissance.
The email and TLS clues are especially useful for finding internal services. A mail server that is exposed to the internet is a target. A certificate that is used by an internal tool may reveal the tool's hostname.
The clues are just candidates. I validate them with the same DNS and HTTP checks.
Scope and responsibility
The takeover finding raises a scope question. The subdomain belongs to the target organization, but the service that hosts the content belongs to a third party. The responsibility for the fix is shared.
I document the third-party platform in the report. The platform may have a specific process for reclaiming the domain. The report should include the steps that the organization needs to take with the platform.
The scope also affects the testing. I do not test the third-party platform itself. I only test the interaction between the subdomain and the platform. The proof of control uses my own account, not an account that belongs to the target.
The responsibility question is part of the impact. A takeover that requires the platform's cooperation is different from a takeover that the organization can fix alone.
Mistakes I make
My biggest mistake is reporting a takeover before proving control. The error page is not enough, because some platforms allow the name to be claimed only by the original account. My second mistake is ignoring the platform's verification requirements. A platform that requires a file changes the takeover process. My third mistake is using a real-looking project name in the test, which could interfere with the target.
The fourth mistake is forgetting to remove the proof. A proof file left on the subdomain is a security issue in itself. The fifth mistake is treating every CNAME to an external platform as a vulnerability. The CNAME is just the first step.
My quick checklist
- Collect subdomains and resolve their CNAME records.
- Compare CNAME targets with takeover-prone platforms.
- Send HTTP requests and look for missing-resource error pages.
- Check whether the platform allows the name to be claimed.
- Register the name with a separate account and a unique random name.
- Upload a proof file and confirm it is served on the subdomain.
- Remove the proof and document the DNS and HTTP evidence.
- Report the business impact, not just the technical condition.
What I would do next time
Next time I want to build the DNS inventory before I start the HTTP checks. The inventory tells me which records are worth checking and which platforms are involved. I also want to spend more time understanding the platform's verification process, because that is where the difference between a confirmed takeover and a false positive is decided. Subdomain takeover is not a single test. It is a chain of DNS, platform, and content checks.