DEV Community

Rasika Dangamuwa
Rasika Dangamuwa

Posted on

Why Subdomain Takeovers Still Happen in Production: 5 Dangling DNS Traps Every DevOps Team Hits

Every engineering team regularly cleans up cloud infrastructure. You tear down a legacy documentation site hosted on GitHub Pages, delete an unneeded S3 staging bucket, or decommission an abandoned Zendesk support desk.

You run your cloud teardown scripts or click delete in the cloud console, and the resource is gone. But in Route 53, Cloudflare, or your company's DNS manager, the CNAME record (docs.example.comexample-docs.github.io or assets.example.comexample-assets.s3.amazonaws.com) stays active.

That single forgotten DNS entry creates a dangling DNS record. Within hours, an automated scanner can detect the unclaimed endpoint, claim the matching resource name on that public cloud provider, and take full control of your subdomain.

Here is why subdomain takeovers still happen in production environments, the 5 common architectural traps that cause them, and how to protect your infrastructure.


1. The Global S3 Bucket Namespace Race

AWS S3 bucket names are globally unique across all AWS accounts. If your domain has a CNAME like:

cdn-assets.example.com.   IN   CNAME   example-old-bucket.s3.amazonaws.com.
Enter fullscreen mode Exit fullscreen mode

When you delete example-old-bucket, that name immediately returns to the global AWS pool. Anyone with an AWS account can run:

aws s3api create-bucket --bucket example-old-bucket --region us-east-1
Enter fullscreen mode Exit fullscreen mode

Once the bucket is created, the attacker configures it for static website hosting. Any browser requesting https://cdn-assets.example.com/bundle.js will load scripts directly from the attacker's bucket. If your Content Security Policy (CSP) trusts *.example.com, this completely bypasses your script execution restrictions.


2. GitHub Pages and the Unclaimed CNAME File

GitHub Pages maps custom domains to user/organization repositories using a CNAME file inside the repository.

When docs.example.com points to your-org.github.io, but the repository is deleted or renamed:

  1. Requests to docs.example.com hit GitHub's edge routers and return 404 There isn't a GitHub Pages site here.
  2. Any GitHub user can create a public repository, enable GitHub Pages, and commit a CNAME file containing docs.example.com.
  3. GitHub automatically provisions a Let's Encrypt SSL certificate via ACME HTTP-01 challenge because DNS already routes traffic to GitHub's servers.

The attacker now serves HTTPS-verified content under your official domain name with zero warnings in the user's browser.


3. Orphaned CDN Endpoints (Fastly, CloudFront, Azure CDN)

Modern CDNs optimize routing by binding custom domain hostnames to distribution endpoints. If you delete a CloudFront distribution or Azure CDN endpoint without purging DNS records, a secondary account on the same CDN provider can claim that domain alias unless strict DNS TXT ownership verification is enabled.

When visiting the dangling domain, the edge CDN responds with distinctive provider-specific fingerprints:

  • AWS S3 / CloudFront: <Code>NoSuchBucket</Code> or Bad Request
  • Fastly: Fastly error: unknown domain: docs.example.com
  • Surge.sh: project not found
  • Ghost: The thing you were looking for is no longer here

If you are auditing your DNS zones, you can test endpoints manually or run your records through a subdomain takeover checker to scan CNAME targets against over 40 known cloud provider takeover fingerprints in your browser.


4. Wildcard DNS Records Masking Stale Ephemeral Preview Deployments

Feature-branch preview environments (e.g., pr-1042.staging.example.com or dev-worker.preview.example.com) are common in modern CI/CD pipelines.

Teams often set a wildcard DNS record:

*.preview.example.com.   IN   CNAME   app-cluster-ingress.us-west-2.elb.amazonaws.com.
Enter fullscreen mode Exit fullscreen mode

If the underlying Kubernetes ingress, load balancer, or Heroku app is destroyed after merging the pull request, the wildcard DNS record remains live. If the multi-tenant routing layer accepts unclaimed hostnames, any tenant on that shared cluster can claim the stale branch subdomain.


5. Why Subdomain Takeover Is Worse Than Defacement: Cookie and OAuth Theft

A compromised subdomain is far more dangerous than simple website defacement:

  1. Session Cookie Hijacking: If your parent site sets session cookies with Domain=.example.com (note the leading dot or absence of strict host-only flags), those session cookies are automatically transmitted to all subdomains. An attacker on docs.example.com can read them directly via JavaScript.
  2. OAuth Redirect Hijacking: Many OAuth 2.0 and OpenID Connect clients use wildcard redirect URIs (e.g., https://*.example.com/oauth/callback) to support multiple environments. An attacker points the OAuth flow to the taken-over subdomain and captures the authorization code or access token.

How to Prevent Dangling DNS in Production

  1. Couple DNS with Infrastructure-as-Code: Never create DNS records manually. Manage CNAME records in the same Terraform or OpenTofu module as the associated resource so terraform destroy tears down the DNS record alongside the cloud asset.
  2. Monitor DNS Hygiene: Schedule periodic audits of all public DNS zones. Inspect any CNAME returning NXDOMAIN, 404, or cloud provider error pages.
  3. Avoid Overly Broad Wildcard Cookies: Always scope session tokens and sensitive auth cookies to the exact host (omit the Domain attribute to default to host-only scoping).

Running an automated audit with a subdomain takeover checker or adding DNS zone linting to your CI/CD pipeline helps catch orphaned records before automated scanners do.

Top comments (0)