Skip to main content
Back to blog
April 24, 2026·Updated May 2, 2026|10 min read|Antoine Duno|Web Security

Subdomain Takeover: What It Is and How to Prevent It

A subdomain takeover lets an attacker serve content from your domain by claiming an abandoned cloud resource. This guide explains the mechanics, shows real-world examples, and gives you a concrete remediation and monitoring workflow.

Antoine Duno

1,408 words

AD

Antoine Duno

Founder of ZeriFlow · 10 years fullstack engineering · About the author

Key Takeaways

  • A subdomain takeover lets an attacker serve content from your domain by claiming an abandoned cloud resource. This guide explains the mechanics, shows real-world examples, and gives you a concrete remediation and monitoring workflow.
  • Includes copy-paste code examples and step-by-step instructions.
  • Free automated scan available to verify your implementation.

Subdomain Takeover: What It Is and How to Prevent It

Subdomain takeover is one of the most underestimated vulnerabilities in web security. It requires no code exploit, no brute-forcing, and no sophisticated tooling. An attacker finds a subdomain that points to a cloud resource nobody owns anymore, registers that resource, and immediately begins serving content from your domain. Victims see a fully trusted URL — staging.yourcompany.com, blog.yourcompany.com, api-old.yourcompany.com — that is now under attacker control.

The consequences range from phishing campaigns to cookie theft (depending on cookie scope) to reputational damage. HackerOne''s bug bounty data consistently lists subdomain takeovers as high-severity findings, with payouts frequently in the $1,000-$5,000 range — which means attackers are actively hunting for them on your domains right now.

The Mechanics of Subdomain Takeover

The vulnerability requires three conditions:

  1. 1You have a DNS record (typically a CNAME) pointing subdomain.yourdomain.com to an external service endpoint.
  2. 2The external service resource (a GitHub Pages repo, Heroku app, S3 bucket, etc.) no longer exists or is unclaimed.
  3. 3The external platform allows anyone to register that same endpoint name.

The attack flow:

DNS lookup: staging.yourcompany.com
→ CNAME → yourcompany.github.io
→ yourcompany.github.io resolves to GitHub Pages IPs
→ GitHub: "No repository configured for yourcompany.github.io" → 404

Attacker creates GitHub account "yourcompany", creates a repository "yourcompany.github.io"
→ GitHub Pages now serves their content at yourcompany.github.io
→ staging.yourcompany.com now serves attacker content

The attacker does not need access to your DNS — they only need access to the external platform, which is often free and open to registration.

Real-World Examples by Platform

GitHub Pages

GitHub Pages is the most commonly exploited vector. When a company shuts down a project or renames a GitHub organization, CNAME records pointing to orgname.github.io become vulnerable.

Indicators:

$ dig staging.example.com CNAME
staging.example.com.  300  IN  CNAME  example-staging.github.io.

$ curl -I https://example-staging.github.io
HTTP/2 404
# Response body: "There isn''t a GitHub Pages site here."

If you see this 404 from GitHub, the subdomain is likely claimable.

Heroku

Heroku apps have URLs like appname.herokuapp.com. When an app is deleted but the DNS CNAME pointing to it remains, anyone can create a new Heroku app with the same name:

subdomain.example.com → CNAME → example-prod-api.herokuapp.com
# App was deleted during a migration

# Attacker:
heroku create example-prod-api
# Now controls subdomain.example.com

Amazon S3

S3 static website hosting uses bucket names that must match the subdomain. If assets.example.com points to assets.example.com.s3-website-us-east-1.amazonaws.com and the bucket is deleted, any AWS user can create a bucket named assets.example.com:

assets.example.com → CNAME → assets.example.com.s3-website-us-east-1.amazonaws.com
# Bucket deleted

$ curl https://assets.example.com.s3-website-us-east-1.amazonaws.com
# Response: NoSuchBucket

# Attacker creates bucket named "assets.example.com" with public website hosting
# Now serves malicious JS files from assets.example.com

This is particularly dangerous for subdomains serving JavaScript files — the attacker can inject malicious scripts into every page that loads assets from that URL.

Other Vulnerable Platforms

PlatformIndicatorRisk Level
Azure App Serviceazurewebsites.net endpoint returns errorHigh
Fastlyfastly.net CNAME, Fastly returns 500/503High
Netlifynetlify.app returns 404High
Ghost (Pro)ghost.io CNAME, domain not claimedMedium
Shopifymyshopify.com CNAME, shop deactivatedMedium
Zendeskzendesk.com CNAME, help center removedMedium
Tumblrtumblr.com CNAME, blog deletedMedium

A comprehensive list of vulnerable services and their fingerprints is maintained at can-i-take-over-xyz.

How Attackers Exploit a Taken-Over Subdomain

Once an attacker controls a subdomain, several attack vectors open:

Phishing — The attacker creates a convincing login page at accounts.yourcompany.com or login.yourcompany.com. Users trust the domain. Password reuse and credential harvesting follow.

Cookie theft — Cookies set with Domain=.yourcompany.com (note the leading dot) are sent by the browser to all subdomains including the taken-over one. If your application sets session cookies this way, the attacker can harvest them.

XSS via asset injection — An attacker who controls static.yourcompany.com can serve malicious JavaScript that any page loading resources from that subdomain will execute.

CORS abuse — If your API allowlists *.yourcompany.com in its CORS policy, the attacker''s origin becomes a trusted CORS origin, enabling cross-origin requests to your API with victim credentials.

Email spoofing — Subdomain control can sometimes be used to pass SPF/DKIM checks if mail infrastructure uses that subdomain, enabling email spoofing from a trusted-looking address.

Tools to Scan for Vulnerable Subdomains

Subzy

bash
# Install
go install github.com/PentestPad/subzy@latest

# Scan a list of subdomains
subzy run --targets subdomains.txt

# Output vulnerable subdomains only
subzy run --targets subdomains.txt --vuln

Nuclei with Subdomain Takeover Templates

bash
# Install nuclei
go install github.com/projectdiscovery/nuclei/v3/cmd/nuclei@latest

# Run subdomain takeover templates against a list
nuclei -l subdomains.txt -t ~/nuclei-templates/takeovers/

# Against a single target
nuclei -u https://staging.example.com -t ~/nuclei-templates/takeovers/

Subjack

bash
go install github.com/haccer/subjack@latest
subjack -w subdomains.txt -t 100 -timeout 30 -ssl -c ~/go/pkg/mod/github.com/haccer/subjack@latest/fingerprints.json

Enumerating Your Subdomains First

Before you can scan for takeovers, you need a comprehensive list of your subdomains:

bash
# subfinder
go install github.com/projectdiscovery/subfinder/v2/cmd/subfinder@latest
subfinder -d yourcompany.com -o subdomains.txt

# amass
go install github.com/owasp-amass/amass/v4/...@master
amass enum -d yourcompany.com -o subdomains.txt

# Certificate Transparency logs (free, no install needed)
curl "https://crt.sh/?q=%.yourcompany.com&output=json" | jq ''.[].name_value'' | sort -u

How to Fix Vulnerable Subdomains

The fix depends on whether you still need the subdomain:

If You No Longer Need the Subdomain

Delete the DNS record. This is the correct fix and the only permanent one:

bash
# Via AWS Route 53 CLI
aws route53 change-resource-record-sets \\
  --hosted-zone-id YOUR_ZONE_ID \\
  --change-batch ''{
    "Changes": [{
      "Action": "DELETE",
      "ResourceRecordSet": {
        "Name": "staging.yourcompany.com",
        "Type": "CNAME",
        "TTL": 300,
        "ResourceRecords": [{"Value": "yourcompany-staging.herokuapp.com"}]
      }
    }]
  }''

If You Still Need the Subdomain

Re-create the resource at the cloud provider before deleting and recreating the DNS record:

  1. 1Create a new Heroku app / GitHub Pages repo / S3 bucket with the same endpoint name
  2. 2Verify it returns a valid 200 response
  3. 3Update or confirm the DNS record is pointing to it correctly

GitHub Pages — Verify Your Custom Domain

GitHub provides domain verification that prevents others from claiming your organization''s domain:

  1. 1Go to your GitHub organization Settings → Pages
  2. 2Add and verify your apex domain (e.g., yourcompany.com)
  3. 3GitHub will refuse to serve GitHub Pages content for your verified domain from any repository you do not own

Preventing Future Subdomain Takeovers

Maintain a DNS inventory — keep a record of every DNS record and the resource it points to. When you decommission a cloud resource, the DNS record deletion should be part of the offboarding checklist.

Automate DNS record cleanup — use infrastructure-as-code (Terraform, Pulumi) where DNS records are created and destroyed together with their associated cloud resources. If the resource is deleted, the DNS record is deleted in the same terraform destroy.

hcl
# Terraform — DNS record tied to resource lifecycle
resource "heroku_app" "staging" {
  name   = "yourcompany-staging"
  region = "us"
}

resource "aws_route53_record" "staging" {
  zone_id = var.hosted_zone_id
  name    = "staging.yourcompany.com"
  type    = "CNAME"
  ttl     = 300
  records = ["${heroku_app.staging.web_url}"]
}
# When heroku_app.staging is destroyed, aws_route53_record.staging goes with it

Use short TTLs on CNAME records — a TTL of 300 seconds (5 minutes) means if a DNS record is compromised, propagation of the fix is fast.

Monitor for DNS changes — set up alerts when DNS records change unexpectedly. ZeriFlow monitors your DNS configuration continuously and alerts you via Slack, Discord, or email when records change or when new vulnerability indicators appear.

Quarterly subdomain audits — run your subdomain enumeration and takeover scan every quarter. Cloud infrastructure changes frequently, and a record that was safe six months ago may now point to a deleted resource.

What to Do If You''ve Already Been Taken Over

  1. 1Immediately delete the CNAME DNS record to break the takeover
  2. 2Rotate any cookies that may have been harvested — force logout all active sessions
  3. 3If the subdomain was serving JavaScript or other assets, audit your CSP to determine which pages loaded content from it
  4. 4Notify affected users if session theft is possible
  5. 5File an abuse report with the platform (GitHub, Heroku, etc.) to have the attacker''s account removed
  6. 6Conduct a full DNS audit to identify any other at-risk records

ZeriFlow scans your DNS records as part of its 80+ security checks, identifying dangling CNAMEs and subdomain configurations that suggest takeover risk. Run a free scan at zeriflow.com and see your full DNS security picture in under 60 seconds.

Ready to check your site?

Run a free security scan in 30 seconds.

Related articles

Keep reading