Web Security

Subdomain Takeover: How It Happens and How to Prevent It

Subdomain takeover lets attackers claim your dangling DNS records and serve content from your domain. Learn how to find dangling subdomains, which services are vulnerable, and how to monitor your DNS.

October 14, 20255 min readShipSafer Team

Subdomain takeover is a vulnerability where an attacker can claim control of a subdomain by exploiting a dangling DNS record. When staging.yourdomain.com points to a cloud service you've decommissioned, anyone can register that service and host content on your subdomain — with a valid SSL certificate, your domain's reputation, and full access to cookies scoped to *.yourdomain.com.

It's consistently rated among the top findings in bug bounty programs and requires no exploitation of your code — just knowledge of your DNS.

How Subdomain Takeover Works

  1. You create staging.yourdomain.com pointing to your-app.herokuapp.com
  2. You shut down the Heroku app but forget to delete the DNS record
  3. The CNAME points to your-app.herokuapp.com — which no longer exists
  4. An attacker registers your-app.herokuapp.com on their Heroku account
  5. They now receive all traffic to staging.yourdomain.com
  6. They serve malicious content, capture cookies, or run phishing campaigns — all from your domain

The attacker's site gets a valid TLS certificate via Let's Encrypt or the platform's cert issuance, so there's no browser warning.

Why This Is Serious

From your domain's subdomain, an attacker can:

  • Set cookies scoped to .yourdomain.com (affecting your main site if cookies use domain=.yourdomain.com)
  • Phish users — email campaigns linking to support.yourdomain.com look legitimate
  • Bypass CORS — if your API whitelists *.yourdomain.com
  • Bypass CSP*.yourdomain.com in script-src allows their scripts
  • Undermine your brand and trust

High-severity findings in bug bounty programs regularly receive $1,000–$5,000+ for subdomain takeovers on production domains.

Services Commonly Vulnerable to Takeover

Any cloud service where you can claim a specific subdomain/instance name and that instance doesn't exist:

ServiceDNS PatternRisk
GitHub Pagesyourdomain.github.ioHigh
Herokuyour-app.herokuapp.comHigh
Netlifyyour-site.netlify.appMedium
Vercelyour-project.vercel.appMedium
AWS S3bucket.s3.amazonaws.comHigh
AWS Elastic Beanstalkapp.elasticbeanstalk.comHigh
Azurevarious .azurewebsites.net, .cloudapp.netHigh
Shopifycustom.myshopify.comMedium
Zendeskyourdomain.zendesk.comMedium
FastlyCNAME to Fastly CDNHigh

A dangling CNAME pointing to an unclaimed instance on any of these services is a takeover risk.

Finding Dangling Subdomains

Step 1: Enumerate all your subdomains

# Using subfinder (passive DNS enumeration)
subfinder -d yourdomain.com -all -o subdomains.txt

# Using amass
amass enum -d yourdomain.com -o subdomains.txt

# From Certificate Transparency logs
curl "https://crt.sh/?q=%.yourdomain.com&output=json" | \
  jq -r '.[].name_value' | sort -u > ct-subdomains.txt

Step 2: Check each subdomain's CNAME

# Check CNAME records
while read subdomain; do
  cname=$(dig CNAME "$subdomain" +short)
  if [ -n "$cname" ]; then
    echo "$subdomain -> $cname"
  fi
done < subdomains.txt

Step 3: Check if CNAME targets exist

# For each CNAME, check if the target resolves
while read subdomain; do
  cname=$(dig CNAME "$subdomain" +short | tr -d '.')
  if [ -n "$cname" ]; then
    target_ip=$(dig A "$cname" +short)
    if [ -z "$target_ip" ]; then
      echo "POTENTIAL DANGLING CNAME: $subdomain -> $cname (no A record)"
    fi
  fi
done < subdomains.txt

Using automated tools

# subjack: checks for dangling CNAMEs against known vulnerable services
go install github.com/haccer/subjack@latest
subjack -w subdomains.txt -t 100 -timeout 30 -o results.txt -ssl

# nuclei templates for subdomain takeover
nuclei -l subdomains.txt -t takeovers/

Prevention and Remediation

1. Delete DNS records before decommissioning services

Make DNS record cleanup part of your decommissioning checklist:

Decommission checklist:
□ Remove service/resource
□ Delete or update DNS CNAME records pointing to the service
□ Wait for DNS TTL expiry before considering cleanup complete
□ Verify: dig CNAME staging.yourdomain.com returns NXDOMAIN

This sounds simple but is the most commonly missed step. Teams focus on deleting the resource and forget the DNS record.

2. Audit your DNS quarterly

Pull all DNS records and check each CNAME and A record resolves correctly:

# Export all DNS records (e.g., from Route 53)
aws route53 list-resource-record-sets \
  --hosted-zone-id YOUR_ZONE_ID \
  --output json | jq -r '.ResourceRecordSets[] | "\(.Type) \(.Name) \(.ResourceRecords[0].Value // .AliasTarget.DNSName // "N/A")"'

Check each CNAME points to an active resource you own.

3. Avoid wildcard DNS records

# ❌ Risky: any subdomain resolves to your IP
*.yourdomain.com A 1.2.3.4

Wildcard records don't directly cause takeovers, but they mask dangling CNAMEs in enumeration and can create other attack surfaces.

4. Use subresource integrity for third-party scripts

If you allow subdomains in your CSP's script-src, use SRI hashes to ensure scripts haven't been replaced:

<script
  src="https://static.yourdomain.com/analytics.js"
  integrity="sha256-abc123..."
  crossorigin="anonymous">
</script>

5. Restrict cookie scope

If possible, don't set cookies with domain=.yourdomain.com (note the leading dot, which covers all subdomains). Cookie theft through a subdomain takeover is only effective if cookies are scoped to the parent domain.

Continuous Monitoring

Set up ongoing monitoring rather than relying on periodic audits:

# GitHub Actions: check for dangling CNAMEs weekly
name: DNS Audit
on:
  schedule:
    - cron: '0 9 * * 1'  # Every Monday 9am

jobs:
  dns-audit:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Install tools
        run: go install github.com/haccer/subjack@latest
      - name: Enumerate subdomains
        run: subfinder -d ${{ secrets.DOMAIN }} -o subdomains.txt
      - name: Check for takeovers
        run: subjack -w subdomains.txt -t 100 -o findings.txt -ssl
      - name: Alert if findings
        if: ${{ hashFiles('findings.txt') != '' }}
        run: cat findings.txt && exit 1

Bug bounty programs are also an effective passive monitoring mechanism — researchers regularly scan for subdomain takeovers, and responsible disclosure provides an early warning system.

subdomain-takeover
dns
attack-surface
reconnaissance
web-security

Check Your Security Score — Free

See exactly how your domain scores on DMARC, TLS, HTTP headers, and 25+ other automated security checks in under 60 seconds.