Back to Articles

SubOver: How Go Concurrency Revolutionized Subdomain Takeover Detection

[ View on GitHub ]

SubOver: How Go Concurrency Revolutionized Subdomain Takeover Detection

Hook

A misconfigured subdomain at Uber once allowed researchers to hijack login.uber.com—pointing it to their own server. SubOver was built to find thousands of these vulnerabilities in minutes, not months.

Context

Subdomain takeover vulnerabilities emerge when an organization's DNS points to external services they no longer control. Imagine a company using GitHub Pages for docs.company.com, then deleting the GitHub repository without removing the DNS CNAME record. An attacker can now create a GitHub Pages site with that exact name and serve malicious content on the company's domain—bypassing cookie policies, stealing credentials, and damaging reputation.

Before tools like SubOver, security researchers manually checked subdomains by visiting them one-by-one, looking for telltale error messages like "There isn't a GitHub Pages site here" or "No such app" on Heroku. This was tedious, slow, and error-prone. Early Python-based tools existed but couldn't scale to scan tens of thousands of subdomains efficiently. Ice3man543 recognized that Go's concurrency model could transform this workflow, creating a tool that could check hundreds of subdomains simultaneously while maintaining a simple, extensible architecture. SubOver emerged from the bug bounty community's need for speed—when you're competing with other researchers to find and report vulnerabilities first, scanning velocity directly translates to earnings.

Technical Insight

CNAME Record

Match Found

No Match

Response Body

Vulnerable

Safe

Subdomain List File

Work Queue Channel

providers.json

Fingerprint Database

Goroutine Pool 10 workers

DNS Resolver

CNAME Matcher

HTTP Prober

Signature Validator

Takeover Report

System architecture — auto-generated

SubOver's architecture elegantly combines three core components: DNS resolution for CNAME discovery, concurrent HTTP probing, and signature-based fingerprinting. The tool reads a newline-delimited list of subdomains, spawns configurable goroutines (default 10), and distributes work across them using Go's channel-based concurrency patterns.

The fingerprinting system relies on a providers.json configuration file that maps service providers to their vulnerability signatures. Each provider entry contains CNAME patterns to match against DNS records and distinctive error messages that indicate an unclaimed service. For example, detecting a takeover-vulnerable GitHub Pages subdomain requires matching a CNAME ending in ".github.io" and finding the text "There isn't a GitHub Pages site here" in the HTTP response. Here's what a typical provider signature looks like:

{
  "name": "GitHub",
  "cname": ["github.io"],
  "response": ["There isn't a GitHub Pages site here.", "For root URLs (like http://example.com/) you must provide an index.html file"],
  "fingerprint": ["github.io"]
}

The concurrency model leverages Go's goroutines to perform I/O-bound operations in parallel. When you run SubOver with a list of 1000 subdomains and 10 threads, it creates a buffered channel as a work queue and spawns 10 goroutines that continuously pull subdomains to check. Each goroutine performs three sequential operations: resolve the subdomain's CNAME record using net.LookupCNAME(), match the CNAME against provider patterns, and if matched, make HTTP/HTTPS requests to check for signature strings in the response body. This architecture means SubOver can maintain 10 concurrent DNS lookups and HTTP requests simultaneously, dramatically reducing total scan time compared to sequential checking.

The signature detection logic implements a straightforward pattern matching algorithm. After fetching the HTTP response body, SubOver iterates through the provider's response array, searching for any matching strings using strings.Contains(). If a match is found, the subdomain is flagged as potentially vulnerable. This approach prioritizes speed and simplicity over sophisticated pattern matching—it's not using regex or complex parsing, just substring searches. The trade-off is intentional: false positives are acceptable in security scanning because they can be manually verified, but false negatives (missing real vulnerabilities) are catastrophic.

One clever architectural decision is the separation of detection logic from provider data. By externalizing service signatures to providers.json, SubOver becomes immediately extensible without code changes. When a new vulnerable service emerges or an existing service changes its error messages, you simply update the JSON file. This design pattern—configuration-driven behavior—is particularly valuable in security tools where threat landscapes evolve rapidly. The downside, as we'll discuss, is the hard dependency this creates on file location.

The tool also implements smart protocol handling, attempting both HTTP and HTTPS connections when checking for fingerprints. Many subdomain takeover vulnerabilities only manifest over specific protocols—some services redirect HTTP to HTTPS while others serve different content. SubOver checks both to maximize detection coverage, though this doubles the HTTP request load per suspicious subdomain.

Gotcha

SubOver's most significant limitation is its discontinued status. The repository README explicitly states "This project is no longer maintained," meaning security researchers are inheriting technical debt when adopting it. As cloud providers update their error messages and new vulnerable services emerge, the providers.json file becomes stale. You'll need to maintain your own fork and keep fingerprints updated—effectively becoming the maintainer of an abandoned project.

The '-a' flag, which checks all hosts regardless of CNAME records, generates excessive false positives and dramatically increases scan time. This option was designed to catch edge cases where vulnerable services might be reached through A records or other DNS configurations, but in practice, it triggers on any service showing similar error messages. Legitimate websites that happen to display text like "not found" or "doesn't exist" get flagged, requiring manual review of hundreds or thousands of false alarms. Unless you have specific intelligence suggesting non-CNAME takeovers in your target scope, avoid this flag entirely.

The hard-coded dependency on providers.json location creates operational fragility. SubOver expects this file in a specific path relative to the binary, and if you're running the tool from different directories or in containerized environments, it silently fails or produces incomplete results. There's no graceful error handling for missing provider data—the tool simply won't detect vulnerabilities for undefined services. This means your deployment process must ensure the JSON file travels with the binary, adding complexity to automation pipelines and Docker containers. Modern Go tools typically embed configuration files using go:embed directives to avoid this exact problem, but SubOver predates that feature.

Verdict

Use SubOver if you're conducting bug bounty research or penetration testing engagements where subdomain takeover is in scope and you need proven, fast detection across the most common vulnerable services. The Go-based concurrency still outperforms many alternatives for large-scale scanning, and the core fingerprints for major platforms like AWS, Heroku, and GitHub remain accurate despite the discontinued status. It's particularly valuable if you're already maintaining a custom providers.json file for your organization's specific threat landscape. Skip SubOver if you're building security automation for long-term production use, need ongoing maintenance and updates, or want modern Go dependency management and error handling. The discontinued status makes it unsuitable for enterprise security platforms where supportability matters. Also skip it if you lack Go development experience to fork and maintain your own version—you will need to update provider fingerprints eventually. Consider actively maintained alternatives like nuclei with subdomain-takeover templates for production environments, or subjack if you prefer similar Go-based tooling with more recent updates.

// ADD TO YOUR README
[![Featured on Starlog](https://starlog.is/api/badge/cybersecurity/ice3man543-subover.svg)](https://starlog.is/api/badge-click/cybersecurity/ice3man543-subover)