What is Subdomain Takeover?
Subdomain takeover occurs when a subdomain points to an external service that has been decommissioned or never properly configured. An attacker can claim the service and serve malicious content from your subdomain.
This vulnerability is dangerous because attackers inherit your domain's reputation, can bypass same-origin policies to steal cookies, and can serve phishing content that appears legitimate.
How Subdomain Takeover Works
Before decommissioning:
blog.company.com ──CNAME──▶ company.wordpress.com ──▶ WordPress Server
After decommissioning (vulnerable):
blog.company.com ──CNAME──▶ company.wordpress.com ──▶ "Site Not Found"
After takeover:
blog.company.com ──CNAME──▶ company.wordpress.com ──▶ Attacker's Content
(Attacker claims this name)
Dangling DNS Records
Dangling DNS records are the root cause. These occur when DNS records continue pointing to resources that no longer exist:
; Common vulnerable scenarios
staging.company.com CNAME old-staging.azurewebsites.net
dev.company.com CNAME project-dev.herokuapp.com
shop.company.com CNAME company.shopify.comCloud Service Fingerprints
Each service has distinctive error pages when unclaimed:
| Service | Fingerprint Pattern |
|---|---|
| AWS S3 | "NoSuchBucket", "The specified bucket does not exist" |
| GitHub Pages | "There isn't a GitHub Pages site here" |
| Heroku | "No such app", "There's nothing here, yet" |
| Azure Web Apps | "404 Web Site not found" |
| Shopify | "Sorry, this shop is currently unavailable" |
| Fastly | "Fastly error: unknown domain" |
Detection Script
import dns.resolver
import requests
class SubdomainTakeoverScanner:
def __init__(self):
self.fingerprints = {
'AWS S3': {
'cnames': ['.s3.amazonaws.com'],
'patterns': ['NoSuchBucket']
},
'GitHub Pages': {
'cnames': ['.github.io'],
'patterns': ["There isn't a GitHub Pages site here"]
},
'Heroku': {
'cnames': ['.herokuapp.com'],
'patterns': ['No such app']
},
'Azure': {
'cnames': ['.azurewebsites.net'],
'patterns': ['404 Web Site not found']
}
}
def resolve_cname(self, subdomain):
try:
answers = dns.resolver.resolve(subdomain, 'CNAME')
return str(answers[0].target).rstrip('.')
except:
return None
def check_http(self, subdomain):
try:
response = requests.get(f'https://{subdomain}', timeout=10, verify=False)
return response.text
except:
return None
def scan(self, subdomain):
cname = self.resolve_cname(subdomain)
if not cname:
return {'subdomain': subdomain, 'vulnerable': False}
for service, config in self.fingerprints.items():
for cname_pattern in config['cnames']:
if cname_pattern in cname.lower():
http_body = self.check_http(subdomain) or ''
for pattern in config['patterns']:
if pattern.lower() in http_body.lower():
return {
'subdomain': subdomain,
'cname': cname,
'service': service,
'vulnerable': True
}
return {'subdomain': subdomain, 'cname': cname, 'vulnerable': False}
# Usage
scanner = SubdomainTakeoverScanner()
result = scanner.scan('blog.example.com')
if result['vulnerable']:
print(f"VULNERABLE: {result['subdomain']} -> {result['cname']}")Prevention Strategies
1. DNS Record Inventory
Maintain an inventory of all DNS records and their purposes:
subdomains:
- name: blog.company.com
type: CNAME
target: company.wordpress.com
owner: marketing
purpose: Company blog
external_service: WordPress.com2. Decommissioning Process
## Service Decommissioning Checklist
1. [ ] Remove DNS records FIRST
2. [ ] Wait for TTL to expire
3. [ ] Verify DNS propagation
4. [ ] Only then decommission the external service
5. [ ] Update DNS inventory documentation3. Automated Monitoring
import schedule
def monitor_subdomains():
subdomains = load_from_inventory()
scanner = SubdomainTakeoverScanner()
for subdomain in subdomains:
result = scanner.scan(subdomain)
if result['vulnerable']:
send_alert(f"VULNERABLE: {subdomain}")
schedule.every(24).hours.do(monitor_subdomains)4. CAA Records
Control which CAs can issue certificates for your domain:
company.com. IN CAA 0 issue "letsencrypt.org"
company.com. IN CAA 0 iodef "mailto:security@company.com"5. Avoid Wildcard DNS
; DANGEROUS: Any subdomain resolves
*.company.com. IN A 203.0.113.1
; SAFER: Explicit records only
www.company.com. IN A 203.0.113.1
api.company.com. IN A 203.0.113.2Impact of Subdomain Takeover
| Attack Vector | Impact |
|---|---|
| Cookie theft | Session hijacking for all subdomains |
| Phishing | Credential theft with trusted domain |
| OAuth hijacking | Account takeover via callback interception |
| Malware distribution | Trusted domain bypasses security tools |
Automated Subdomain Takeover Detection
Subdomain takeover vulnerabilities require ongoing monitoring as your DNS configuration changes and external services are provisioned or decommissioned.
RedVeil's AI-powered penetration testing platform identifies subdomain takeover vulnerabilities by analyzing your DNS records, fingerprinting external services, and testing for claimable resources. The platform provides proof-of-concept evidence and clear remediation guidance.
Scan your subdomains for takeover vulnerabilities with RedVeil →