High-performance passive subdomain enumeration engine for effortless asset discovery and rapid reconnaissance
Features • Installation • Configuration • Usage • Examples • Shell • Providers • Output • Docker
Subdominator is a high-performance passive subdomain enumeration engine. It leverages 73 OSINT sources — certificate transparency logs, search engines, threat intelligence feeds, DNS datasets, and more — to map your target's full attack surface in seconds.
Built on Python's async/await stack (asyncio + aiohttp), it handles 100K+ subdomains per run without memory spikes thanks to its disk-backed findings cache.
- 73 passive OSINT sources — CT logs, search engines, threat intel, DNS archives, and more
- Recursive enumeration — automatically scan discovered subdomains to any depth
- Disk-backed cache — 100K+ subdomains per run with stable memory usage
- Concurrent execution — configurable parallelism with async-first architecture
- Interactive audit shell — search, filter, export, and manage historical findings
- Multiple output formats — plain text, JSONL stream, JSON report, HTML report
- SQLite persistence — findings are saved automatically to a local SQLite database; query and export via the interactive shell
- Health diagnostics — verify connectivity and API key status before a run
- Docker-ready — pre-built images on GHCR, no local Python setup required
uv tool install subdominatorpip install --upgrade subdominatorgit clone https://github.com/RevoltSecurities/Subdominator.git
cd Subdominator
uv syncpip install "subdominator[reports]"
# or
uv tool install "subdominator[reports]"Requires Python 3.13+
Subdominator stores its API key config in a YAML file. On first run it creates the template automatically at:
~/.config/subdominator/provider-config.yaml
Open that file and add your keys under each provider. Each entry is a list so you can supply multiple keys — Subdominator will pick one at random per run:
# ~/.config/subdominator/provider-config.yaml
shodan:
- YOUR_SHODAN_KEY
censys:
- YOUR_CENSYS_ID:YOUR_CENSYS_SECRET
github:
- ghp_token1
- ghp_token2
# Providers that share the same RapidAPI key:
# coderog, rapidfinder, rapidscan → rapidapi
rapidapi:
- YOUR_RAPIDAPI_KEY
# Aliases: whoisxml → whoisxmlapi, zoomeyeapi → zoomeye
whoisxmlapi:
- YOUR_WHOISXMLAPI_KEY
zoomeye:
- YOUR_ZOOMEYE_KEYUse a custom config path with --config-path / -cp:
subdominator -d example.com -cp /path/to/my-config.yamlAll settings can be driven by environment variables instead of CLI flags. The prefix is SUBDOMINATOR_:
| Environment variable | Equivalent flag | Effect |
|---|---|---|
SUBDOMINATOR_SSL_VERIFY=false |
--insecure / -k |
Disable SSL certificate verification on all HTTP connections |
SUBDOMINATOR_PROXY=http://host:port |
--proxy / -p |
Route all HTTP requests through this proxy |
SUBDOMINATOR_TIMEOUT=30 |
--timeout / -t |
Override default request timeout |
SUBDOMINATOR_CONCURRENCY=16 |
--concurrency / -c |
Override default concurrency |
Priority: CLI flags always win over environment variables. If both are set, the CLI flag takes effect.
Standard proxy env vars (HTTP_PROXY, HTTPS_PROXY, NO_PROXY) are also respected automatically via aiohttp's trust_env — no prefix needed.
| Config key | Used by providers |
|---|---|
rapidapi |
coderog, rapidfinder, rapidscan |
whoisxmlapi |
whoisxml |
zoomeye |
zoomeyeapi |
subdominator [flags]
| Flag | Short | Description |
|---|---|---|
--domain |
-d |
Single target domain |
--domain-list |
-dL |
File with one domain per line (bulk mode) |
| Flag | Short | Description |
|---|---|---|
--all |
Use all 73 resources (includes disabled-by-default ones) | |
--include-resources |
-ir |
Comma-separated list of resources to use |
--exclude-resources |
-er |
Comma-separated list of resources to skip |
--list-resources |
-ls |
Print resource catalog with auth requirements |
--dork |
-dk |
Custom search dork (Google and supported engines) |
Disabled by default:
commoncrawl,github,virustotal,waybackarchive— these are slow or rate-limited. Use--allor-irto include them explicitly.
| Flag | Short | Description |
|---|---|---|
--recursive-depth |
-rd |
Max recursion depth for discovered subdomains (default: 0) |
--concurrency |
-c |
Parallel resource slots (default: 8) |
--timeout |
-t |
HTTP timeout in seconds (default: 20.0) |
--retries |
-rt |
Retries per failed request (default: 3) |
--retry-backoff |
-rb |
Backoff multiplier in seconds between retries (default: 1.0) |
--proxy |
-p |
HTTP proxy URL (e.g. http://127.0.0.1:8080) |
--insecure |
-k |
Skip SSL certificate verification |
| Flag | Short | Description |
|---|---|---|
--config-path |
-cp |
Path to custom provider config YAML |
--show-config-path |
-scp |
Print the active provider config path and exit |
| Flag | Short | Description |
|---|---|---|
--output |
-o |
Write plain-text results to a file |
--output-directory |
-oD |
Directory to save per-domain files (bulk mode) |
--html |
-oh |
Generate an HTML report (requires jinja2) |
--report-json |
-rj |
Write a JSON summary report |
--json |
-j |
Stream JSONL to stdout ({"domain":...,"subdomain":...,"resource":...}) |
--table |
-tb |
Print findings as a formatted terminal table |
--show-summary |
-ss |
Print a run summary after completion |
--show-resource-stats |
-srs |
Print per-resource finding counts and durations |
| Flag | Short | Description |
|---|---|---|
--db-path |
-dp |
Custom path for the SQLite database file |
--no-db |
-nd |
Disable automatic DB persistence for this run |
--save-db |
-sd |
Explicitly enable DB persistence (on by default) |
--shell |
-sh |
Open the interactive audit shell |
--health-check |
-hc |
Verify connectivity and API key status |
--update |
-up |
Update Subdominator to the latest release |
--release |
-release |
Show release notes for the latest version |
--verbose |
-v |
Enable debug logging |
--no-color |
-nc |
Disable colored output |
DB persistence is enabled by default. Every run saves findings to the local SQLite database automatically. Use
--no-dbto skip persistence for a specific run, or--db-pathto write to a different file.
Basic single-domain scan:
subdominator -d example.comSave results to a file:
subdominator -d example.com -o results.txtRecursive enumeration (depth 2):
subdominator -d example.com -rd 2Stream JSON for pipeline integration:
subdominator -d example.com -j | jq .subdomainUse only specific sources:
subdominator -d example.com -ir shodan,censys,securitytrailsExclude slow sources:
subdominator -d example.com -er commoncrawl,waybackarchiveBulk scan from a file, save per-domain results:
subdominator -dL domains.txt -oD ./output/Disable DB persistence for a one-off scan:
subdominator -d example.com -ndUse a custom SQLite database path:
subdominator -d example.com -dp /data/recon.dbFull scan with all sources + HTML report:
subdominator -d example.com --all -oh report.htmlCustom Google dork:
subdominator -d example.com -ir google -dk site:example.com -inurl:wwwHealth check before a run:
subdominator --health-checkPipe-safe output (no BrokenPipeError):
subdominator -d example.com | head -20
subdominator -d example.com -j | grep "api\."Launch the audit shell with --shell or -sh:
subdominator --shellThe shell provides a persistent terminal interface for querying and managing historical findings stored in the SQLite database.
| Command | Description |
|---|---|
domains |
List all stored root domains with finding counts |
domain <root> |
Show stats summary for a stored domain |
findings <root> |
Show all stored findings for a domain |
runs [root] |
Show recent stored runs |
add <root> <file> |
Import and merge findings from a text file |
add domain <root> <file> |
Legacy-style alias for the above |
export <root> <path> [txt|json|html] |
Export findings to a file |
delete <root> |
Delete a domain and all its findings |
resources |
List resource catalog with auth markers |
config |
Show active config and database paths |
update |
Update Subdominator to the latest version |
release |
Show release notes for the latest version |
clear |
Clear the terminal |
exit / quit |
Exit the shell |
Resource auth markers in resources output:
*— API key required~— API key optional (works without, more results with)-— No auth needed
One subdomain per line. Pipe-safe. Use -o results.txt to save.
api.example.com
mail.example.com
dev.example.com
Newline-delimited JSON, one finding per line. Designed for jq, grep, and pipeline tools.
{"domain":"example.com","subdomain":"api.example.com","resource":"shodan"}
{"domain":"example.com","subdomain":"mail.example.com","resource":"crtsh"}A full standalone HTML report. Requires the jinja2 optional dependency (pip install "subdominator[reports]").
--show-summary prints an overview table (total findings, resource counts, duration). --show-resource-stats adds a per-resource breakdown with individual finding counts and durations.
A full structured JSON summary of the run, including resource execution metadata, useful for feeding into other tools.
Findings are automatically saved to SQLite at ~/.local/share/subdominator/subdominator.db on every run. Use --no-db to skip for a specific run, or --db-path to write to a custom path. Query and export from the interactive --shell.
Note on crt.sh and PostgreSQL: The
crtshprovider internally queries the public crt.sh certificate transparency database over a direct PostgreSQL connection (usingasyncpg). This is a read-only query to the crt.sh public server — Subdominator itself does not expose or require any PostgreSQL connection for its own data storage.
73 sources total. Auth column: key = API key required, optional = works without a key (more results with one), free = no auth needed.
Sources marked † are disabled by default (slow or heavily rate-limited). Include them with
--allor-ir <name>.
| Name | URL | Notes |
|---|---|---|
abuseipdb |
https://abuseipdb.com/ | |
anubis |
https://jldc.me/anubis | |
commoncrawl † |
https://index.commoncrawl.org/ | Slow, large dataset |
crtsh |
https://crt.sh | Certificate Transparency |
cyfare |
https://cyfare.net/ | |
digitorus |
https://www.digitorus.com/ | |
hackertarget |
https://hackertarget.com/ | |
hudsonrock |
https://cavalier.hudsonrock.com/ | |
myssl |
https://myssl.com | |
racent |
https://face.racent.com/ | |
rapiddns |
https://rapiddns.io/ | |
reconcloud |
https://recon.cloud/ | |
riddler |
https://riddler.io/ | |
shrewdeye |
https://shrewdeye.app/api | |
sitedossier |
https://www.sitedossier.com/ | |
shodanx |
https://github.com/RevoltSecurities/Shodanx | |
thc |
https://thc.org/ | |
threatcrowd |
https://threatcrowd.org/ | |
threatminer |
https://www.threatminer.org/ | |
waybackarchive † |
https://archive.org/wayback | Very slow |
| Name | URL | Notes |
|---|---|---|
alienvault |
https://otx.alienvault.com | More results with key |
reconeer |
https://www.reconeer.com/ | More results with key |
submd |
https://api.sub.md/ | More results with key |
Pre-built images are published to the GitHub Container Registry on every release.
Pull and scan:
docker run --rm -it ghcr.io/revoltsecurities/subdominator:latest -d example.comSave output to the current directory:
docker run --rm -it \
-v $(pwd):/output \
ghcr.io/revoltsecurities/subdominator:latest \
-d example.com -o /output/results.txtUse a custom provider config:
docker run --rm -it \
-v /path/to/config:/config \
ghcr.io/revoltsecurities/subdominator:latest \
-cp /config/provider-config.yaml -d example.comBuild the image locally:
docker build -t subdominator -f Docker/Dockerfile .git clone https://github.com/RevoltSecurities/Subdominator.git
cd Subdominator
uv sync --group dev
python -m pytest tests/ -vBuild a distribution:
uv buildProject structure:
src/subdominator/
├── cli/ # app.py (entry point), shell.py (audit shell)
├── core/ # models, settings, constants, provider_config
├── http/ # retryable.py (aiohttp wrapper)
├── output/ # reports.py (HTML), writers
├── resources/
│ ├── base.py # BaseResource
│ ├── catalog.py # RESOURCE_CATALOG (73 entries)
│ ├── registry.py # ResourceRegistry + DEFAULT_DISABLED_RESOURCES
│ └── providers/ # 73 individual provider modules
├── services/ # enumerator.py (async orchestration)
└── storage/ # database.py, repository.py (SQLite)
Subdominator performs passive reconnaissance only — it queries public APIs and datasets and does not send traffic directly to the target. No self-updates happen without explicit --update / shell update command. All HTTP interactions go through the RetryableHttpClient which logs requests at debug level.
MIT © RevoltSecurities
Built with care by the RevoltSecurities team. If Subdominator helps your work, a ⭐ on GitHub goes a long way.

