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 72 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.
Features
- 72 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
Installation
Recommended — uv tool (fastest)
uv tool install subdominator
pip (traditional)
pip install --upgrade subdominator
From source
git clone https://github.com/RevoltSecurities/Subdominator.git
cd Subdominator
uv sync
With HTML report support
pip install "subdominator[reports]"
# or
uv tool install "subdominator[reports]"
Requires Python 3.13+
Configuration
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_KEY
Use a custom config path with --config-path / -cp:
subdominator -d example.com -cp /path/to/my-config.yaml
Environment variables
All 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.
Key aliases
| Config key | Used by providers |
|---|---|
rapidapi |
coderog, rapidfinder, rapidscan |
whoisxmlapi |
whoisxml |
zoomeye |
zoomeyeapi |
Usage
subdominator [flags]
Input
| Flag | Short | Description |
|---|---|---|
--domain |
-d |
Single target domain |
--domain-list |
-dL |
File with one domain per line (bulk mode) |
Resource selection
| Flag | Short | Description |
|---|---|---|
--all |
Use all 72 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.
Runtime
| 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 |
Config
| Flag | Short | Description |
|---|---|---|
--config-path |
-cp |
Path to custom provider config YAML |
--show-config-path |
-scp |
Print the active provider config path and exit |
Output
| 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 |
Storage & diagnostics
| 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.
Examples
Basic single-domain scan:
subdominator -d example.com
Save results to a file:
subdominator -d example.com -o results.txt
Recursive enumeration (depth 2):
subdominator -d example.com -rd 2
Stream JSON for pipeline integration:
subdominator -d example.com -j | jq .subdomain
Use only specific sources:
subdominator -d example.com -ir shodan,censys,securitytrails
Exclude slow sources:
subdominator -d example.com -er commoncrawl,waybackarchive
Bulk 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 -nd
Use a custom SQLite database path:
subdominator -d example.com -dp /data/recon.db
Full scan with all sources + HTML report:
subdominator -d example.com --all -oh report.html
Custom Google dork:
subdominator -d example.com -ir google -dk site:example.com -inurl:www
Health check before a run:
subdominator --health-check
Pipe-safe output (no BrokenPipeError):
subdominator -d example.com | head -20
subdominator -d example.com -j | grep "api\."
Interactive Shell
Launch the audit shell with --shell or -sh:
subdominator --shell
The shell provides a persistent terminal interface for querying and managing historical findings stored in the SQLite database.
Shell commands
| 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
Output Formats
Plain text (default)
One subdomain per line. Pipe-safe. Use -o results.txt to save.
api.example.com
mail.example.com
dev.example.com
JSONL stream (-j)
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"}
HTML report (-oh report.html)
A full standalone HTML report. Requires the jinja2 optional dependency (pip install "subdominator[reports]").
Summary (-ss / -srs)
--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.
JSON report (-rj report.json)
A full structured JSON summary of the run, including resource execution metadata, useful for feeding into other tools.
Database (automatic)
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.
Providers
72 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>.
Free (no auth)
| 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 |
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 |
Optional API key
| 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 |
Requires API key
Docker
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.com
Save output to the current directory:
docker run --rm -it \
-v $(pwd):/output \
ghcr.io/revoltsecurities/subdominator:latest \
-d example.com -o /output/results.txt
Use 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.com
Build the image locally:
docker build -t subdominator -f Docker/Dockerfile .
Development
git clone https://github.com/RevoltSecurities/Subdominator.git
cd Subdominator
uv sync --group dev
python -m pytest tests/ -v
Build a distribution:
uv build
Project 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 (72 entries)
│ ├── registry.py # ResourceRegistry + DEFAULT_DISABLED_RESOURCES
│ └── providers/ # 72 individual provider modules
├── services/ # enumerator.py (async orchestration)
└── storage/ # database.py, repository.py (SQLite)
Security
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.
License
MIT © RevoltSecurities
Built with care by the RevoltSecurities team. If Subdominator helps your work, a ⭐ on GitHub goes a long way.
Metadata
Release files for subdominator 3.0.3
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| subdominator-3.0.3.tar.gz | 563.4 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| subdominator-3.0.3-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 664.0 kB
Release files / subdominator-3.0.3.tar.gz
| Download URL | subdominator-3.0.3.tar.gz |
|---|---|
| Size | 563.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
0332ac09e40b92d013a3c94c2ddf22d9b41cf248bc21a1c502078c3841e81139
|
|
BLAKE2b-256 checksum How to use checksums |
80a7ce7f6f7f07a9275b269e7cad4d228792cf7024726abc22aac4d706cae243
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.12.23 {"installer":{"name":"uv","version":"0.12.23","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / subdominator-3.0.3-py3-none-any.whl
| Download URL | subdominator-3.0.3-py3-none-any.whl |
|---|---|
| Size | 100.6 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
a180c7fed9cc4e1e7e9254e551032fe09c7c8adfa89a6a6fd354fee2ddd375fd
|
|
BLAKE2b-256 checksum How to use checksums |
a342c63cb1f515f0000d66f84a10790ab3d6f2d519f87c80c88455797b70b8eb
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.12.23 {"installer":{"name":"uv","version":"0.12.23","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|