DEV Community

Davi
Davi

Posted on Originally published at blog.mago.team

Subdomain Takeover: When an Abandoned CNAME Becomes an Attack Vector

A researcher registers an abandoned S3 bucket, waits 72 hours, and starts receiving 8M+ requests, including CloudFormation templates, unsigned binaries, and SSLVPN configurations from Fortune 500 CI/CD pipelines. No exploit was used. The attacker simply showed up where the victim had forgotten to close the door.

Dangling CNAMEs are not a DNS problem. They are a decommissioning failure. The DNS record keeps working exactly as designed; the fault lies in the process that separates the cloud resource lifecycle from the lifecycle of the record pointing to it.

The CNAME Is Still Active. The Service Is Not. That Gap Is the Vulnerability.

Subdomain takeover requires no technical vulnerability to exploit. It only requires that the cloud resource name be globally unique and claimable after deletion.

When an organization deletes an app on Heroku, a bucket on S3, or a service on Azure App Service, the resource name returns to the global available pool. Any account on the same provider can register that name immediately. The CNAME record, until it is removed from DNS, keeps routing traffic to the new resource owner.

EdOverflow's can-i-take-over-xyz GitHub repository catalogs 76+ services with confirmed takeover paths. Nuclei maintains 72+ detection templates based on per-service fingerprints, with specific error messages like "NoSuchBucket" for S3, "There isn't a GitHub Pages site here." for GitHub Pages, and "No such app" for Heroku. DNS TTL may delay cache propagation by minutes to hours, but once the new resource is active, traffic is already routed.

The critical distinction: DNS did not fail. The team that decommissioned the cloud resource failed to remove the corresponding DNS record. These two lifecycles are managed by different teams, and the gap between them is the attack surface.

Four Documented Cases That Show the Full Severity Spectrum

The attack vector is identical across all cases. The blast radius depends on how much trust the organization placed in that subdomain.

Uber / saostatic.uber.com (2016) — complete authentication bypass. Researcher Arne Swinnen found that saostatic.uber.com had a CNAME pointing to a disabled CloudFront distribution. He claimed the distribution under his own account. Uber's SSO set cookies scoped to *.uber.com; controlling any subdomain meant capturing valid sessions on riders.uber.com, vault.uber.com, and partners.uber.com. HackerOne report #219205 resulted in a $5,000 bounty. A static assets subdomain delivered full account access for any user.

SentinelOne S3 research (October 2024 to January 2025) — supply chain compromise. Researchers identified approximately 150 abandoned S3 buckets still referenced by active CNAMEs from government agencies, Fortune 500 companies, and open-source projects. They claimed the buckets and monitored for 4 months. The result: 8M+ requests received, including CloudFormation templates, unsigned pre-compiled binaries, SSLVPN configurations, and container images. Zero DNS changes were needed; the victims' own CI/CD pipelines did the work, continuing to pull dependencies from buckets that already belonged to third parties.

Shopify / s3.shopify.com — CSP bypass. The s3.shopify.com record had a CNAME pointing to an unclaimed S3 bucket. Registering the bucket would allow serving arbitrary content under the shopify.com origin. Shopify's ecosystem CSP policies trusted *.shopify.com; any script served from the bucket would execute without restriction in contexts relying on that wildcard. $500 bounty on HackerOne, report #207576.

Snapchat / blog.snapchat.com — phishing with a legitimate-looking URL. The blog.snapchat.com subdomain pointed to a deactivated blog platform instance. Claiming the platform account meant controlling the content served under blog.snapchat.com. The end user would see a completely valid URL with no visual indicator of compromise. Phishing under a verified domain is categorically more effective than phishing with a lookalike domain, and technically indistinguishable to the average user.

Cloud Sprawl Is Making This Problem Exponentially Worse

Every sprint that provisions a new cloud service without a corresponding decommissioning task in the backlog is generating future attack surface.

SentinelOne identified 1,250+ subdomain takeover risks for customers in 2024. A single customer had more than 2,000 exploitable DNS records. IONIX estimates that organizations know only 62% of their actual external exposure; 38% of the attack inventory is completely blind to the teams that should be defending it.

A corporate apex domain routinely accumulates 25,000+ subdomains spread across infra teams, marketing, developers, and SaaS vendors. Azure alone exposes 14 services with globally unique, claimable namespaces after deletion: App Service, Traffic Manager, CDN, Blob Storage, Container Registry, API Management, SQL Server, Redis Cache, Service Bus, Container Instance, AI Search, Data Lake Store, Virtual Machine, and Cloud Services. can-i-take-over-xyz catalogs 76+ confirmed services and is continuously updated by the community.

Ownership fragmentation is the multiplying factor. When no team knows who is responsible for a specific DNS record, no one removes it at the right time. Decommissioned SaaS vendors, subdomains from ended marketing campaigns, and forgotten staging environments form the most common inventory of dangling CNAMEs in organizations with more than 200 people.

Detection Is a Solved Problem: Most Teams Never Run the Pipeline

The tooling to find dangling CNAMEs at scale exists, is free, and runs in under 2 minutes for most domains.

The most direct pipeline has 3 chained stages:

subfinder -d target.com | httpx -silent | nuclei -tags takeover
Enter fullscreen mode Exit fullscreen mode

subfinder enumerates subdomains through multiple passive sources. httpx filters hosts that respond over HTTP and discards silent ones. nuclei applies 72+ fingerprint templates, identifying the specific error message for each service to confirm the vulnerability.

Subjack offers parallel verification across 30+ services with customizable fingerprints and separate output by status: confirmed, unresolved, and vulnerable. dnsReaper supports automated periodic scanning with SARIF output, integrating natively into CI/CD security gates. intel.mago.team monitors dangling CNAMEs continuously as part of the attack surface exposure module.

The gap is not technical. It is operational: most teams run this pipeline once, in response to an incident, and never incorporate it as a recurring monitoring process. A weekly scheduled scanner would find dangling CNAMEs before any external researcher does.

The Fix Happens at Decommissioning Time, Not at Discovery

Reactive scanning finds dangling CNAMEs after the compromise window is already open. The only durable mitigation is making DNS record removal a mandatory step in the cloud resource decommissioning workflow.

The correct sequence inverts what most teams do in practice: remove the DNS record before decommissioning the resource, not after. Keeping the resource active while DNS is removed eliminates any takeover window. OWASP documents this sequence inversion as the core of the vulnerability.

Azure implemented domain verification via TXT records for App Service: the platform requires proof of ownership before accepting a custom domain binding, blocking the vector by design. This approach can be replicated internally with a verification TXT record before CNAME removal, ensuring the domain is not claimable during the interval between DNS removal and resource deletion.

Wildcards in CNAMEs and CSP directives need to be eliminated. Any subdomain takeover under a wildcard like *.example.com automatically scales to full session hijack or script injection across the entire ecosystem. DNS ownership requires explicit mapping: each record must have an owning team, a cloud resource ID, and a documented decommissioning contact.

Every sprint that provisions a Heroku dyno, an Azure App Service, or an Elastic Beanstalk environment without a corresponding decommissioning task is accumulating attack debt. The attacker does not need to break in. They only need to register what you left behind.

Top comments (0)