Crown Jewel Targets
Subdomain takeover is high-value because it allows an attacker to serve content from a trusted, company-owned domain — bypassing browser same-origin trust, phishing filters, and user skepticism simultaneously.
Highest payout contexts:
- Subdomains of major SaaS brands (Shopify, Snapchat, Mozilla, Yelp) where the trusted domain has user session context
- CDN-backed subdomains (Fastly, CloudFront) where CNAME points to unclaimed origins
- Third-party service integrations: UserVoice, WordPress.com, GitHub Pages, GitLab Pages, Heroku, Zendesk
- Preview/staging/dev subdomains (
new.,preview.,course.,delivery.,addons-preview.) — abandoned after feature launches - Subdomains used for OAuth redirect URIs or SSO endpoints — these pay highest
Asset types that matter most:
- CNAME records pointing to deprovisioned third-party services
- NS delegations to abandoned zones
- A records pointing to unallocated cloud IPs (less common)
- GitLab/GitHub Pages with unclaimed project namespaces
Attack Surface Signals
DNS signals:
CNAMEpointing to*.github.io,*.gitlab.io,*.fastly.net,*.herokudns.com,*.wordpress.com,*.uservoice.com,*.zendesk.com,*.s3.amazonaws.com,*.azurewebsites.net,*.netlify.app- NXDOMAIN or
SERVFAILon the CNAME target while the parent record still exists - NS records delegating to registrars where the zone is no longer registered
HTTP response signals:
"There isn't a GitHub Pages site here""NoSuchBucket"(S3)"The specified bucket does not exist""No such app"(Heroku)"Sorry, this shop is currently unavailable"(Shopify)"This UserVoice subdomain is available""Do you want to register"(any domain parking page)- HTTP 404 with provider-specific error templates
- Fastly:
"Fastly error: unknown domain"
Tech stack signals:
- Response headers:
X-Served-By: cache-*(Fastly),X-GitHub-Request-Id,Server: Netlify CNAMEchain resolving to provider infrastructure but returning provider 404- SSL cert issued to provider wildcard (
*.fastly.net) rather than company domain
Step-by-Step Hunting Methodology
-
Enumerate all subdomains for the target using passive + active sources:
subfinder -d target.com -allamass enum -passive -d target.comassetfinder --subs-only target.com- Certificate transparency:
crt.sh/?q=%.target.com
-
Resolve all subdomains and flag those with:
- NXDOMAIN responses
- CNAME pointing to a third-party provider
cat subdomains.txt | dnsx -a -cname -o resolved.txt -
Cross-reference CNAMEs against known vulnerable provider fingerprints using
nucleiorsubjack:subjack -w subdomains.txt -t 100 -timeout 30 -ssl -c fingerprints.json nuclei -l subdomains.txt -t takeovers/ -
Manual verification for each flagged subdomain:
dig CNAME subdomain.target.com— confirm CNAME existsdig A <cname-target>— confirm NXDOMAIN or no resolutioncurl -sk https://subdomain.target.com— check for provider error string
-
Confirm claimability — attempt to register the resource:
- GitHub Pages: check if
<username>.github.io/<repo>or org page is unclaimed - GitLab Pages: check project namespace
- S3: attempt
aws s3api create-bucket --bucket <bucketname> - UserVoice/Zendesk/WordPress: visit registration URL
- Fastly: check if origin hostname is unregistered
- GitHub Pages: check if
-
Claim the resource (only enough to prove control — do NOT serve malicious content):
- Create a minimal index page with your HackerOne username and a timestamp
- Take screenshot showing your content served on
subdomain.target.com
-
Document the chain: CNAME record → provider target → unclaimed resource → your content
-
Assess impact escalation:
- Does the subdomain appear in OAuth redirect allowlists?
- Does it share cookies with parent domain (
domain=.target.com)? - Is it referenced in the app's CSP?
- Can it receive authenticated API calls?
-
Write report before releasing the claim (some programs want to verify first)
Payload & Detection Patterns
Bulk CNAME extraction and NXDOMAIN detection:
# Extract CNAMEs and check if target resolves
while read sub; do
cname=$(dig +short CNAME "$sub" | head -1)
if [ -n "$cname" ]; then
result=$(dig +short A "$cname")
if [ -z "$result" ]; then
echo "[POTENTIAL] $sub -> $cname (NXDOMAIN)"
fi
fi
done < subdomains.txt
Nuclei takeover scan:
nuclei -l subdomains.txt -t ~/nuclei-templates/http/takeovers/ -severity medium,high,critical
subjack with SSL:
subjack -w subdomains.txt -t 100 -timeout 30 -ssl -c $GOPATH/src/github.com/haccer/subjack/fingerprints.json -v
Provider fingerprint grep patterns:
curl -sk "https://$subdomain" | grep -iE \
"there isn't a github pages|no such bucket|no such app|this uservoice|fastly error: unknown domain|do you want to register|sorry, this shop|project not found|404 not found|unclaimed"
Check if subdomain is in scope for cookies (shared parent domain):
curl -Isk "https://target.com" | grep -i "set-cookie" | grep "domain=.target.com"
Fastly-specific detection:
curl -sI "https://subdomain.target.com" -H "Host: subdomain.target.com" | grep -i "fastly\|x-served-by\|x-cache"
curl -sk "https://subdomain.target.com" | grep -i "fastly error"
S3 unclaimed bucket check:
aws s3api head-bucket --bucket <extracted-bucket-name> 2>&1 | grep -i "NoSuchBucket\|403\|404"
GitLab Pages specific:
dig CNAME sub.target.com
# If pointing to *.gitlab.io — visit the gitlab.io URL directly
# 404 from gitlab.io project = claimable
Common Root Causes
-
Service offboarding without DNS cleanup — Developer removes a Heroku app, UserVoice account, or WordPress site but never deletes the CNAME record. DNS lives forever; service does not.
-
Staging/preview infrastructure abandoned post-launch —
course.,new.,preview.,beta.subdomains provisioned for a product launch, pointed at a third-party, then forgotten when the campaign ends. -
Subdomain provisioned by a third-party team — Marketing sets up a UserVoice or Zendesk subdomain via IT, product sunset kills it, but DNS is owned by engineering who doesn't know.
-
CDN misconfiguration without origin validation — Fastly and similar CDNs historically allowed any domain to "claim" a backend hostname by creating a service pointing to it. Unregistered origin hostnames become claimable.
-
GitHub/GitLab Pages namespace not reserved — Organization renames, user accounts deleted, or repos made private/deleted while the Pages CNAME still points to the old namespace.
-
Wildcard DNS entries —
*.target.compointing to a cloud provider means any unclaimed subdomain potentially resolves to claimable infrastructure. -
Acquired/divested company DNS not cleaned — Post-acquisition, former brand subdomains (like
oberlo.comunder Shopify) retain CNAMEs to services that are no longer paid for.
Bypass Techniques
Defense: Manual fingerprint review before publishing
- Bypass: Use alternative error strings — providers change their 404 pages. Maintain an up-to-date fingerprint list. Some providers show different errors on HTTP vs HTTPS. Test both.
Defense: Scope restrictions (only main domain in scope)
- Bypass: Check program's asset list carefully —
*.target.comwildcards often include subdomains implicitly. Escalate impact to get it in scope.
Defense: "Can't reproduce" responses due to timing
- Bypass: Screenshot immediately after claiming. Record a video walkthrough. The window can be short for popular subdomains.
Defense: HTTPS certificate mismatch blocking proof
- Bypass: Some providers (GitHub Pages, Netlify) auto-provision TLS for claimed d