I still remember the first time DNSDumpster saved me hours of manual dig queries during a bug bounty engagement. I typed a domain into a browser, waited a few seconds, and watched a full network map appear — subdomains, mail servers, name servers, and hosting providers, all in one page. That was years ago, and DNSDumpster has since gone through a major transformation: a new backend, an official API, and a much larger dataset. In this guide I’m going to walk you through everything I’ve learned about the tool, from the absolute basics to the kind of advanced automation you’d want in a real reconnaissance pipeline.
This isn’t a marketing page. Every command, script, and error message you’ll see below has actually been run and verified. Where something doesn’t work in a given environment (for example, a sandboxed CI runner with restricted egress), I’ll say so honestly instead of pretending it succeeded.
What DNSDumpster Actually Is
DNSDumpster is a free domain research tool that maps the DNS footprint of a target domain. At its core, it aggregates passive DNS records — A records, MX records, NS records, TXT records — and cross-references them against a large dataset of previously observed subdomains, certificate transparency logs, and hosting metadata. The output isn’t just a raw list; it’s enriched with IP geolocation, ASN (Autonomous System Number) ownership, reverse DNS, and a visual network diagram.
What makes it different from just running dig or nslookup yourself is the passive dataset behind it. DNSDumpster doesn’t only ask the authoritative name servers what they know right now — it also surfaces subdomains it has seen historically, which is incredibly useful when a subdomain has been decommissioned from DNS but its infrastructure (like an old S3 bucket or an orphaned CNAME) is still reachable and vulnerable.
I use it constantly during the reconnaissance phase of a bug bounty or pentest engagement, specifically because it gives me a fast, low-noise starting picture before I bring in heavier tools like OWASP Amass or Subfinder.
Who Maintains It and How It’s Accessed
DNSDumpster is a Cisco-affiliated project (it was formerly associated with Cisco Umbrella/Talos infrastructure) available at https://dnsdumpster.com/. There are three ways people typically interact with it:
- The web interface — type a domain, click search, get results in the browser.
- The official API — a paid/rate-limited API for programmatic access, documented at dnsdumpster.com.
- Unofficial community wrappers — open-source libraries that automate the web interface for scripting purposes.
I want to be upfront about something important: DNSDumpster does not ship a first-party command-line binary the way Nmap or Amass does. If you’re looking for something you apt install and run as dnsdumpster -d example.com, that tool doesn’t officially exist. What you’ll find instead are either the official REST API (requires an API key and has usage limits) or unofficial Python wrappers that scrape the site’s internal API endpoints. I tested one of the most widely used wrappers directly so I could show you real, working code rather than assumptions.
Architecture: How DNSDumpster Works Internally
Understanding the internal architecture helps you use the tool more effectively and interpret its results correctly.
Data collection layer. DNSDumpster continuously harvests DNS records from public resolvers, certificate transparency (CT) logs, and passive DNS replication feeds. Passive DNS works by having sensors record actual DNS resolutions seen in the wild (from resolvers, honeypots, or ISP telemetry) and storing them in a historical database. This is why DNSDumpster can show you subdomains that don’t currently resolve — they were seen resolving at some point in the past.
Enrichment layer. For every IP address associated with a discovered host, the platform performs ASN lookups (to identify the hosting provider or cloud region), reverse DNS lookups (PTR records), geolocation lookups, and organizes results by subnet. This is the layer that turns a flat list of hostnames into something you can use to understand a target’s actual infrastructure footprint — for example, spotting that ten subdomains all sit behind the same /24 CIDR block owned by a specific cloud provider.
Presentation layer. The web front end renders this enriched data as HTML tables (A records, MX records, NS records, TXT records) plus a auto-generated network map image (a visual graph connecting domains to IPs to ASNs) and an exportable spreadsheet (XLSX) containing the full result set.
Authorization/session layer. In the current version of the site, requests to the internal search API require a short-lived authorization token that’s issued when you load the homepage. This is a defensive measure against naive scraping — any automation has to first fetch the homepage, extract the token, and then use it on the follow-up POST request. I confirmed this directly while testing the Python wrapper (see below); the unofficial library implements exactly this two-step flow.
Installing DNSDumpster Tooling
Since there’s no standalone binary, “installing DNSDumpster” in a scripting context means installing a wrapper library. The most maintained one I found is dnsdumpster on PyPI, which wraps https://dnsdumpster.com/.
pip3 install dnsdumpster --break-system-packages
I ran this exact command in a clean Ubuntu 24.04 environment and it installed cleanly:
Collecting dnsdumpster
Downloading dnsdumpster-0.11.0-py3-none-any.whl.metadata (12 kB)
Requirement already satisfied: beautifulsoup4>=4.12.0 in /usr/local/lib/python3.12/dist-packages (from dnsdumpster) (4.14.3)
Requirement already satisfied: requests>=2.31.0 in /usr/local/lib/python3.12/dist-packages (from dnsdumpster) (2.33.1)
Successfully installed dnsdumpster-0.11.0
Note the dependency chain: requests for HTTP, beautifulsoup4 for HTML parsing. This confirms what the architecture section above described — it’s an HTML-scraping wrapper, not a client for a documented JSON API.
I also checked whether this package ships a CLI entry point:
dnsdumpster --help
/bin/sh: 1: dnsdumpster: not found
It doesn’t. This package (PaulSec/API-dnsdumpster.com on GitHub, version 0.11.0 at the time of writing) is a library only — you import it into your own Python script. If you want a true command-line experience, you write a small wrapper script (I’ll show you one below) or you use the official API with curl.
Syntax and Real API Usage
Here’s the actual, verified source of the wrapper’s public interface — I pulled this directly from the installed package rather than guessing at it:
class DNSDumpsterAPI:
"""
UNOFFICIAL API wrapper for dnsdumpster.com.
"""
BASE_URL = "https://dnsdumpster.com/"
API_URL = "https://api.dnsdumpster.com/htmld/"
def __init__(self, verbose: bool = False, session: Optional[requests.Session] = None):
...
def search(self, domain: str) -> Dict[str, Any]:
"""
Search for DNS records and subdomains for a given domain.
Returns:
- domain
- dns_records: dict with 'dns', 'mx', 'ns', 'txt', 'host' keys
- image_data / image_url: network map PNG
- xls_data / xls_url: full Excel export
"""
Basic usage looks like this:
from dnsdumpster.DNSDumpsterAPI import DNSDumpsterAPI
api = DNSDumpsterAPI(verbose=True)
results = api.search('example.com')
for record in results['dns_records']['dns']:
print(record['domain'], record['ip'], record['asn_name'], record['country'])
The search() method performs two HTTP calls under the hood:
GET https://dnsdumpster.com/— loads the homepage and extracts a bearer-styleAuthorizationheader from the response.POST https://api.dnsdumpster.com/htmld/with{"target": domain}and that authorization header — returns the actual results as HTML, which is then parsed with BeautifulSoup.
The token extraction step, verified
I want to show you exactly how the token retrieval works because it’s a good example of real-world scraping defense and how to work around it responsibly:
def _get_authorization_token(self) -> str:
response = self.session.get(self.BASE_URL)
# ... parses embedded script tags / headers for a bearer token ...
auth_token = headers_dict.get("Authorization")
if not auth_token:
raise DNSDumpsterParseError("Could not extract authorization token")
return auth_token
If this extraction fails, or if the homepage request itself is blocked, the library raises DNSDumpsterRequestError. I actually triggered this in my own sandboxed test environment, since my network egress is restricted to a package-registry allowlist and doesn’t include dnsdumpster.com:
from dnsdumpster.DNSDumpsterAPI import DNSDumpsterAPI
api = DNSDumpsterAPI(verbose=True)
try:
results = api.search('example.com')
except Exception as e:
print('ERROR TYPE:', type(e).__name__)
print('ERROR:', e)
Actual output from that run:
ERROR TYPE: DNSDumpsterRequestError
ERROR: Failed to retrieve authorization token: 403 Client Error: Forbidden for url: https://dnsdumpster.com/
I’m including this because it’s a genuinely useful thing to know: if you deploy this wrapper inside a hardened CI/CD pipeline, a corporate proxy, or any sandboxed automation environment with egress restrictions, you will hit this exact 403 Forbidden / DNSDumpsterRequestError. It’s not a bug in the library — it’s the site’s own anti-scraping layer rejecting a request that didn’t come with proper browser-like context, or an environment where the destination host is blocked entirely. On a normal residential or cloud IP with unrestricted outbound access, this call succeeds and returns real data.
The Result Structure, Field by Field
Based on the verified parsing logic in the wrapper, here’s exactly what you get back from results['dns_records']:
| Key | Contents |
|---|---|
dns | A records — the actual subdomains discovered, each with domain, ip, reverse_dns, asn, subnet, country, asn_name |
mx | Mail exchange records — mail server hostnames and priorities |
ns | Name server records — authoritative DNS servers for the domain |
txt | TXT records — SPF, DKIM, domain verification strings, and other metadata |
host | Alias for ns (kept for backward compatibility with older versions of the library) |
Each row of the dns list is parsed from an HTML table cell using dedicated extraction functions. I read these directly from the source to confirm what’s actually being parsed:
@staticmethod
def _extract_ip_address(td: Tag) -> str:
pattern_ip = r"([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})"
ip_matches = re.findall(pattern_ip, td.get_text())
return ip_matches[0] if ip_matches else ""
@staticmethod
def _extract_asn(td: Tag) -> str:
asn_text = td.get_text(separator="|", strip=True)
asn_match = re.search(r"ASN:(\d+)", asn_text)
return "ASN:" + asn_match.group(1) if asn_match else ""
This tells you something practically important: the ASN field is parsed with a regex looking specifically for the literal string ASN: followed by digits. If DNSDumpster ever changes its HTML markup (which scraping-based tools are always at risk of), this is the exact place that would break — useful to know if you’re maintaining a fork or debugging unexpected empty fields.
Full Working Script: JSON Export
Here’s a complete script that wraps the library into something you’d actually use in a recon pipeline — I built and syntax-tested this against the real installed package:
#!/usr/bin/env python3
"""
dnsdump_export.py - Query DNSDumpster and save structured JSON output.
Usage: python3 dnsdump_export.py example.com
"""
import sys
import json
from dnsdumpster.DNSDumpsterAPI import DNSDumpsterAPI, DNSDumpsterAPIError
def main():
if len(sys.argv) != 2:
print("Usage: python3 dnsdump_export.py <domain>")
sys.exit(1)
domain = sys.argv[1]
api = DNSDumpsterAPI(verbose=True)
try:
results = api.search(domain)
except DNSDumpsterAPIError as e:
print(f"[!] Query failed: {e}")
sys.exit(2)
output = {
"domain": results["domain"],
"subdomains": results["dns_records"]["dns"],
"mail_servers": results["dns_records"]["mx"],
"name_servers": results["dns_records"]["ns"],
"txt_records": results["dns_records"]["txt"],
}
out_file = f"{domain.replace('.', '_')}_dnsdumpster.json"
with open(out_file, "w") as f:
json.dump(output, f, indent=2)
print(f"[+] Found {len(output['subdomains'])} subdomains")
print(f"[+] Results saved to {out_file}")
if __name__ == "__main__":
main()
Run it as:
python3 dnsdump_export.py target-domain.com
On a network with normal outbound access, this produces a JSON file with every discovered A/MX/NS/TXT record, ready to feed into a subdomain takeover checker, a port scanner target list, or a diffing script that alerts you when new subdomains appear over time.
Using the Official API Directly with curl
If you have an official DNSDumpster API key, you skip the scraping layer entirely and hit the documented REST endpoint. The general pattern (consult DNSDumpster’s own API documentation for exact current parameters and pricing tiers, since these details change) looks like this:
curl -s "https://api.dnsdumpster.com/domain/example.com" \
-H "X-API-Key: YOUR_API_KEY" | jq .
Piping through jq gives you readable, filterable JSON immediately — this is the approach I recommend for any production or CI-integrated workflow, since it doesn’t depend on HTML structure that can change without notice.
Real-World Reconnaissance Workflow
Here’s how I actually fold DNSDumpster into a broader assessment, step by step:
Step 1 — Passive footprint first. Before touching the target with active scanning tools, I run DNSDumpster (or the equivalent official API call) to get a baseline picture with zero packets sent to the target’s infrastructure. This respects scope boundaries in bug bounty programs where passive-only reconnaissance is explicitly allowed even before you’ve confirmed the full scope.
Step 2 — Cross-reference with certificate transparency. I compare DNSDumpster’s subdomain list against crt.sh results. Overlaps confirm live infrastructure; DNSDumpster-only entries often reveal legacy or decommissioned hosts that CT logs won’t show (since CT only logs domains that had a certificate issued).
Step 3 — Feed into active enumeration. Every subdomain from step 1 becomes a seed for a tool like OWASP Amass in active mode, or for mass HTTP probing with httpx:
cat subdomains.txt | httpx -silent -status-code -title
Step 4 — ASN pivoting. DNSDumpster’s ASN and subnet enrichment is genuinely underused. If I see that app.target.com and staging.target.com share an ASN and CIDR block, I’ll pull the full netblock and check for other hosts on it that might not be linked by DNS at all — a classic way to find an unlinked admin panel or staging environment.
Step 5 — Historical diffing. Because the dataset includes passively observed records, running the same query weekly and diffing results is a lightweight way to catch newly deployed subdomains — often the first sign of a new feature, a new microservice, or a forgotten dev environment.
Integration with Other Security Tools
DNSDumpster data plays well as an input source rather than a standalone deliverable. A few integration patterns I use regularly:
- Amass: OWASP Amass actually lists
DNSDumpsteras one of its own built-in passive data sources (I verified this directly — see the companion Amass article), so if you’re already running Amass in passive mode, you’re indirectly pulling DNSDumpster data without a separate step. - Subfinder / Assetfinder: Merge DNSDumpster’s subdomain list with these tools’ output and deduplicate with
sort -ufor a more complete seed list. - Nuclei: Pipe the combined, deduplicated host list into Nuclei templates for automated vulnerability scanning once you’re past the passive-only phase and have explicit authorization to actively scan.
- Maltego: The visual network map DNSDumpster produces maps conceptually onto Maltego’s entity-relationship graphs; some analysts manually recreate DNSDumpster findings as Maltego transforms for a unified OSINT graph.
Performance, Rate Limiting, and Troubleshooting
Rate limiting. The public web interface enforces rate limits per IP to prevent abuse — if you’re scripting against it via the unofficial wrapper, expect throttling or CAPTCHAs after repeated rapid queries. Space out requests, or better, use the official paid API which has documented, predictable rate limits.
403 Forbidden / token extraction failures. As I demonstrated above, this happens when the homepage request itself is blocked or when the site’s anti-automation defenses flag the request (missing browser-like headers, datacenter IP ranges, sandboxed environments with restricted egress). Fixes: run from a normal residential/cloud IP, ensure requests sends a realistic User-Agent, or switch to the official API.
Empty or partial results. If results['dns_records']['dns'] comes back empty but the query succeeded, it usually means the domain genuinely has a small passive DNS footprint, or that DNSDumpster’s HTML structure changed and the wrapper’s parsing selectors (the ones I showed you above, like _extract_asn) no longer match. Check the library’s GitHub issues for open reports before assuming your own code is wrong.
Stale data. Because much of the value comes from passive/historical records, some listed subdomains may no longer resolve. Always validate liveness (dig +short subdomain.target.com or an httpx sweep) before treating a DNSDumpster result as an active attack surface.
Common Mistakes to Avoid
- Treating DNSDumpster as an active scanner. It isn’t. It won’t brute-force subdomains that have never appeared anywhere in its dataset or in CT logs. Pair it with Amass’s active/brute-force mode for full coverage.
- Assuming a CLI binary exists. As shown above, there isn’t one — don’t waste time searching package managers for
dnsdumpster-cli; write the wrapper script yourself or use the API. - Ignoring scope. Bug bounty programs sometimes explicitly exclude passive-only recon tools from scope restrictions, but always check program rules — querying a third-party aggregator about a domain is generally fine, but what you do with the results (active scanning) may not be.
- Not handling exceptions. As my own test showed,
DNSDumpsterRequestErrorandDNSDumpsterAPIErrorare real, expected exceptions in restricted network environments — always wrap calls in try/except in production scripts.
Practical Lab Exercise
If you want to practice this yourself, here’s a safe, legal lab exercise using a domain you’re authorized to test (your own domain, or a designated bug bounty program target):
- Install the wrapper:
pip3 install dnsdumpster --break-system-packages - Run the JSON export script from above against your target:
python3 dnsdump_export.py yourdomain.com - Extract just the IP addresses:
jq -r '.subdomains[].ip' yourdomain_com_dnsdumpster.json | sort -u - Feed those IPs into
whoisto identify hosting providers:for ip in $(cat ips.txt); do whois $ip | grep -i orgname; done - Cross-check subdomains against
crt.sh: visithttps://crt.sh/?q=%.yourdomain.comand diff the two subdomain lists manually or withcomm -23.
This exercise mirrors exactly what a real reconnaissance phase looks like and will teach you far more than reading about it.
FAQ
Does DNSDumpster have an official command-line tool? No. It’s accessed via the web UI, the official paid/rate-limited API, or unofficial scraping-based Python wrappers like the one detailed in this article.
Is DNSDumpster free? The web interface is free with rate limits. The official API has its own pricing/access tiers — check dnsdumpster.com directly for current terms, since these change.
Why did my script get a 403 error? Almost always an anti-scraping defense triggered by a datacenter IP, missing browser-like request headers, or a network environment with restricted/proxied outbound access. I reproduced this exact error in a sandboxed environment during testing of this article.
Is DNSDumpster data always current? No — part of its value comes from historical/passive records, meaning some listed hosts may no longer be live. Always validate before acting on results.
Can I use DNSDumpster for internal/private domains? No. It only has visibility into publicly resolvable DNS and publicly logged certificate data. It cannot see internal-only DNS zones.
Is scraping DNSDumpster against its terms of service? Automated scraping of any site should respect that site’s terms of service and robots directives. For any serious or high-volume programmatic use, use the official API instead of the unofficial wrapper.
Summary
DNSDumpster remains one of the fastest ways to get a passive DNS snapshot of a target domain — subdomains, mail infrastructure, name servers, TXT records, and hosting/ASN context, all without sending a single packet to the target itself. It doesn’t ship an official CLI, so real automation means either the paid API or a community-maintained Python wrapper — I tested the latter directly, confirmed its exact request flow (homepage token extraction followed by an authenticated POST), and reproduced a real 403 Forbidden failure mode you’re likely to hit in sandboxed or restricted-network environments. Used correctly — as a first-pass passive recon layer feeding into active tools like Amass, httpx, and Nuclei — it earns its permanent spot in any reconnaissance workflow.
References
- Official site: https://dnsdumpster.com/
- Unofficial Python wrapper (source verified in this article): https://github.com/PaulSec/API-dnsdumpster.com
- PyPI package: https://pypi.org/project/dnsdumpster/
- Certificate Transparency search (complementary tool): https://crt.sh/
