I want to take you through a day of what's called subdomain hunting. It's the lowest-effort, highest-impact recon work in the security playbook. I'll walk you through four hunts — anonymized but composite-realistic, drawn from work we've done with permission for various clients over the last year — and at the end I'll explain what each one means, what the attacker chain looks like after, and what the defense looks like before.
The reason to read this in the hunt-log format, rather than as a checklist, is that you'll come away with a feel for how trivially these attacks work, which is the only thing that motivates teams to actually fix the underlying issue. The technical explanation does not produce the same urgency as watching the hunt happen.
It's 9 AM. Coffee in hand. Notebook open. Let's go.
Hunt 1 — Fortune 500 bank (9:14 AM)
The target is a global bank. Their primary domain has somewhere north of 800 subdomains, which is normal for a company of this size — every business unit, every marketing campaign, every internal tool, every regional site, all hanging off the parent.
My first move is enumeration. I run amass enum -d bank.example -passive in one terminal and subfinder -d bank.example -all in another. Three minutes later, I have a list of 847 subdomains. About 600 of them resolve to something. About 247 of them point at IPs that aren't owned by the bank — those are the interesting ones.
Now I do the second move: dig each of those 247 against the DNS CNAME records to find what they point at. I'm specifically looking for CNAMEs pointing at one of the dozens of cloud services that have the takeover pattern. The canonical reference is the can-i-take-over-xyz repository on GitHub — it tracks 76 services and the takeover status of each.
I get three hits.
The first hit points at a Heroku app: quarterly-investor-update-2018.herokuapp.com. I open Heroku, sign up for a free account (which I already have for this kind of work), and try to create a new app with the name quarterly-investor-update-2018.
It's available.
This is the moment that, after a few hundred of these, still gives me a small jolt. The name is available. The bank's CNAME points at it. Whatever I deploy to that Heroku app will load when anyone in the world visits quarterly-investor-update-2018.bank.example.
I do not deploy anything malicious. I deploy a single static HTML page that says, in plain text, "This domain is currently misconfigured. If you believe you have reached this page in error, please contact security@bank.example. — Authorized security testing in progress."
I take a screenshot. I move on. The whole hunt took 18 minutes.
What I would have done with that subdomain if I hadn't been authorized: hosted a perfect replica of the bank's login page, signed with the legitimate wildcard certificate that covers *.bank.example, sent emails to customers from noreply@bank.example linking to it (the email would pass SPF and DKIM because the bank itself is the sender), and harvested credentials. The first thousand customers to click the link would not have a meaningful chance of detecting the attack. The browser would show the green padlock. The URL would be a real bank subdomain. The page would be pixel-identical to the real one.
Cost of the attack: zero. Time: 18 minutes. Total credentials harvested in a six-hour campaign before someone notices: in the thousands.
Hunt 2 — mid-market SaaS (10:31 AM)
Different target, smaller company. About 80 subdomains. I run the same enumeration. I find a CNAME pointing at d3kx8s9w-saas-corp.azureedge.net. Azure CDN.
The Azure CDN class of takeover is interesting because it requires a slightly different exploitation step. You can't simply create an Azure account and claim that exact endpoint name — Azure assigns the endpoint identifier when you create a new CDN profile, and you don't get to pick most of it. But there's a known technique: you create your own CDN profile, then use Azure's API to claim a specific endpoint name when the previous one has been released back to the pool.
I check the date when the original endpoint was likely deleted by looking at the Wayback Machine snapshots of the subdomain. The last snapshot showing real content is from 2022. The CNAME has been dangling for three years.
I run the Azure claim procedure. It succeeds. I now control whatever loads at marketing.saas-corp.example.
This hunt took 47 minutes — the longest of the day, because the Azure CDN takeover has more steps. The Heroku, GitHub Pages, and S3 versions are much faster (six to ten minutes is typical). Each cloud provider's takeover has its own playbook. can-i-take-over-xyz documents the playbook for each.
The Azure case is also a useful reminder that "this provider isn't vulnerable" is a moving target. Microsoft has patched the takeover behavior for several Azure services over the years; researchers have found new techniques in adjacent services. The 2025 update to can-i-take-over-xyz shows several services that flipped from "not vulnerable" to "vulnerable" in the last 18 months because of changes in how the providers handle endpoint reclamation.
Hunt 3 — state university (12:05 PM)
I want to include this one because universities are the most commonly takeover-vulnerable organizations on the public internet, and the consequences are different from corporate cases.
The target has roughly 1,200 subdomains. The university has been online since the early 1990s. There are subdomains pointing at things that were decommissioned during the Clinton administration.
The first hit I get is on a GitHub Pages CNAME: hackathon-2019.university.edu → cool-name-here.github.io. The hackathon ran for one weekend in 2019. The GitHub Pages site was hosted by a then-undergraduate who has since graduated. The CNAME was never removed.
I claim it. GitHub Pages takeovers are among the easiest in the catalog — create a repo, enable Pages, set the custom domain in the repo settings, and you're live. The takeover took eight minutes.
What's interesting about university subdomains is that the cookie-tossing escalation we covered in our CSRF article applies disproportionately. Universities typically run a centralized SSO (Shibboleth, CAS, Okta) with cookies scoped to .university.edu. Every subdomain — including the one I just took over — can write to those cookies. A cookie I write from my GitHub Pages site can be read by the university's actual SSO portal, the registrar, the library system, the email service, anything else inheriting the cookie scope.
The chain from "I control hackathon-2019.university.edu" to "I have a session cookie that the university's email system trusts" is two steps. The first step is the takeover. The second is the cookie-tossing CSRF.
For a university, the practical impact is access to student records, financial aid information, faculty email accounts, and research data — including ITAR-protected research at universities that handle defense contracts. The takeover cost me eight minutes. The downstream impact would have been measured in lawsuits.
I report it. The university security team responds within four hours. The CNAME is deleted within a day. There is no public disclosure because universities, unlike most companies, rarely run formal bug bounty programs — but the response is professional and prompt.
Hunt 4 — state government (2:18 PM)
The last hunt of the day. State government domain, about 400 subdomains. I find a CNAME pointing at an S3 bucket name: tax-forms-archive-2017.s3.amazonaws.com.
S3 bucket takeover is a special case because the namespace is global. When the original bucket was deleted, the name went back into the global pool. Anyone with an AWS account can claim any deleted bucket name, subject to AWS's rate limits.
I claim the bucket. It takes six minutes. I now control whatever loads at tax-forms-archive-2017.state.gov.example.
The October 2024 SentinelOne research is worth mentioning here. Researchers acquired approximately 150 deleted AWS S3 buckets that had previously been referenced by software update channels, deployment pipelines, and shared infrastructure. Over a few months, those 150 buckets received over 8 million HTTP requests, including requests for software updates, deployment artifacts, and configuration files. The buckets had been deleted by their original owners. Other organizations were still pointing at them, expecting the original content.
That research is, structurally, the same attack as Hunt 4 — except instead of taking over a single subdomain's web presence, the researchers took over a chunk of the cloud's package distribution infrastructure. The S3 takeover class scales in ways the CNAME takeover doesn't, because S3 references aren't just in DNS — they're in scripts, in deployment pipelines, in update mechanisms.
For the state government hunt specifically: the abandoned tax-forms bucket name appears in third-party guidance documents from 2017 telling residents to visit that URL to download tax forms. The URL still appears in PDFs hosted on the state's main site. People still type it. Whatever I put in that bucket gets served as the state's tax forms.
The downstream impact: malware-laced PDFs, distributed under the state's brand, to people specifically looking for tax forms (a target population that is, on average, less technically sophisticated and more trusting of state government). The phishing potential is acute.
4 PM — what the day adds up to
Four hunts, four organizations, four successful takeovers. Total time: about three hours of actual work. Total spend: zero (free tiers of Heroku, Azure, GitHub Pages, AWS).
If I were an attacker rather than a researcher under authorization, what could the day have produced?
From the bank: a credential-harvesting campaign against banking customers, hosted on a real-bank subdomain with a real-bank certificate.
From the SaaS: cookie tossing into the main product, account takeover of paid customers, exfiltration of business data.
From the university: SSO cookie poisoning, access to student records, ITAR research data exposure.
From the state government: malware distributed as official tax forms to a vulnerable population.
The blast radius of the four takeovers, combined, is meaningfully larger than the blast radius of most "critical" CVEs that make headlines. The technical sophistication required is zero. The cost is zero. The detection — by the targets — was, in every case before we reported, also zero.
Why this keeps happening
The technical answer is simple. DNS records outlive the services they point at. When a marketing campaign ends, when a Heroku app is deleted, when an S3 bucket is decommissioned, when a GitHub Pages site is removed — the DNS CNAME that pointed at it usually doesn't get cleaned up. The cloud provider releases the name back into the pool. Anyone can claim it.
The organizational answer is harder. The team that created the DNS record is rarely the team that's around when the underlying service is deleted. Marketing teams set up campaign subdomains and rotate every two years. Contractors create dev environments and leave the company. Acquisitions add a thousand subdomains to your inventory, most of which nobody on the acquiring company has ever heard of. The DNS record is an artifact of a decision made by someone who is no longer responsible for the consequences of it.
SentinelOne flagged more than 1,250 subdomain takeover risks for its clients in 2024 alone. Silent Push reported that a single customer discovered over 2,000 exploitable DNS records requiring immediate remediation. The scale is large because the underlying organizational dynamic is universal.
The Hazy Hawk campaign — what happens when attackers do this at scale
In February 2025, a threat actor named Hazy Hawk was caught doing exactly the work I described above, except across thousands of targets at once. The reported victims included the U.S. CDC, Deloitte, PwC, Ernst & Young, and dozens of other Fortune 500 and government targets.
The Hazy Hawk operation appears to have been a systematic mass-scan of dangling DNS records across the public internet. Every CNAME pointing at an unclaimed cloud resource was a candidate. The operator claimed thousands and used them for malware distribution, SEO poisoning, and credential harvesting — typically using the trust of the parent brand to make the malicious content look legitimate.
The reason Hazy Hawk could do this at scale is that the underlying problem — abandoned DNS records — is universal, and the detection is rare. Most organizations have no inventory of their own subdomains, much less of which ones are dangling. The attacker scanned faster than the defenders cleaned up.
The defenses, in order of how cheap they are
Three layers, in increasing order of effort and decreasing order of "you can do this today."
One: run a scanner against your own DNS this week.
The tools that work, free, today: can-i-take-over-xyz as the reference, Subzy, Nuclei with the subdomain-takeover template pack (72 templates as of the latest update), BadDNS (the most recent open-source entrant, released early 2025). Pick one, point it at your DNS, run it. The whole exercise takes an hour. The findings are usually surprising.
Most of our clients, when they run this for the first time, find between three and twenty exposed subdomains. Some of them are old. Most of them are forgotten. All of them are urgent.
Two: build a DNS inventory and a decommissioning checklist.
You need to know every subdomain you own, what it points at, and who owns it. A spreadsheet works. A CMDB works. A document on a wiki works. What doesn't work is "we'll remember." Most companies we audit cannot, in real time, produce their own DNS records.
And — equally important — when a service is decommissioned, the DNS record that pointed at it must be deleted. Make it a checklist item in your runbook for any service shutdown. Make it part of your offboarding procedure when a contractor leaves with a Heroku app under their personal account. The reason this attack works is that DNS records outlive the services they point at. The fix is a process change, not a technical one.
Three: tighten your cookie scoping (the cookie-tossing defense).
Even if a subdomain gets taken over, the damage is limited if the takeover can't reach your main application's cookies. The default for many companies — Domain=.yourcompany.com on the session cookie — means every subdomain can read and write the main app's cookies. The fix is to scope cookies to Domain=app.yourcompany.com, the specific host, not the parent.
This is a small change. It significantly limits the blast radius of a takeover. We cover the cookie-tossing attack class in detail in the CSRF article; the defense applies here directly.
The dangling-S3 extension
One additional defense, specifically for the S3-bucket version of the attack. AWS now offers S3 Object Ownership controls and, more importantly, you can register specific bucket names you've used and have AWS prevent them from being reclaimed by other accounts. This is opt-in and relatively new (2024-2025); few teams have rolled it out. If you've ever created and deleted an S3 bucket whose name appeared in a public artifact (a script, a documentation file, a deployment pipeline), this control is worth knowing about.
The pattern across the four hunts
If you re-read the four hunts, the bugs share a single shape. Someone created a DNS record. The underlying service was decommissioned. The DNS record stayed. The cloud provider released the name. An attacker — or, in this case, a researcher with permission — claimed the name. The takeover took anywhere from six to forty-seven minutes.
The technical step that enables the attack is identical in every case. The variation is only in which cloud service the abandoned CNAME points at — Heroku, Azure CDN, GitHub Pages, S3, and seventy-some other services from the can-i-take-over-xyz list.
The defense is also identical. Inventory your DNS. Delete records when services are decommissioned. Scope cookies tightly. Run a takeover scanner weekly.
None of those defenses are hard. The reason the attack class is alive is that almost no organization does all four. The reason it stays alive is that the cost of doing them feels speculative ("nobody is targeting us") until the day it isn't ("we are in the news, and the news is bad").
One last thought, for the founders
If you're not the engineer who runs your DNS — if you're the founder, the CTO, the head of security, the person who signs the checks — the question to ask is short.
"Can our team, in the next thirty minutes, produce a list of every subdomain we own and tell me which ones currently point at services we no longer use?"
If the answer is yes, congratulations. You are in the small minority. If the answer is no, that is the engineering project for next sprint. Not because we said so. Because Hazy Hawk's next campaign is already running, and the criterion for being in it is exactly the criterion you just failed.
The fix is hours. The cost of not fixing is what a researcher in our chair, with a different ethic and a different paycheck, could do in three hours on a Tuesday afternoon.
That, more than any technical detail in the article above, is the point.