README.md

May 17, 2026 · View on GitHub

Subdominator

High-performance passive subdomain enumeration engine for effortless asset discovery and rapid reconnaissance

FeaturesInstallationConfigurationUsageExamplesShellProvidersOutputDocker

PyPI version Python GitHub release GitHub last commit License: MIT 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.


Features


  • 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

Installation

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 variableEquivalent flagEffect
SUBDOMINATOR_SSL_VERIFY=false--insecure / -kDisable SSL certificate verification on all HTTP connections
SUBDOMINATOR_PROXY=http://host:port--proxy / -pRoute all HTTP requests through this proxy
SUBDOMINATOR_TIMEOUT=30--timeout / -tOverride default request timeout
SUBDOMINATOR_CONCURRENCY=16--concurrency / -cOverride 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 keyUsed by providers
rapidapicoderog, rapidfinder, rapidscan
whoisxmlapiwhoisxml
zoomeyezoomeyeapi

Usage

subdominator [flags]

Input

FlagShortDescription
--domain-dSingle target domain
--domain-list-dLFile with one domain per line (bulk mode)

Resource selection

FlagShortDescription
--allUse all 73 resources (includes disabled-by-default ones)
--include-resources-irComma-separated list of resources to use
--exclude-resources-erComma-separated list of resources to skip
--list-resources-lsPrint resource catalog with auth requirements
--dork-dkCustom search dork (Google and supported engines)

Disabled by default: commoncrawl, github, virustotal, waybackarchive — these are slow or rate-limited. Use --all or -ir to include them explicitly.

Runtime

FlagShortDescription
--recursive-depth-rdMax recursion depth for discovered subdomains (default: 0)
--concurrency-cParallel resource slots (default: 8)
--timeout-tHTTP timeout in seconds (default: 20.0)
--retries-rtRetries per failed request (default: 3)
--retry-backoff-rbBackoff multiplier in seconds between retries (default: 1.0)
--proxy-pHTTP proxy URL (e.g. http://127.0.0.1:8080)
--insecure-kSkip SSL certificate verification

Config

FlagShortDescription
--config-path-cpPath to custom provider config YAML
--show-config-path-scpPrint the active provider config path and exit

Output

FlagShortDescription
--output-oWrite plain-text results to a file
--output-directory-oDDirectory to save per-domain files (bulk mode)
--html-ohGenerate an HTML report (requires jinja2)
--report-json-rjWrite a JSON summary report
--json-jStream JSONL to stdout ({"domain":...,"subdomain":...,"resource":...})
--table-tbPrint findings as a formatted terminal table
--show-summary-ssPrint a run summary after completion
--show-resource-stats-srsPrint per-resource finding counts and durations

Storage & diagnostics

FlagShortDescription
--db-path-dpCustom path for the SQLite database file
--no-db-ndDisable automatic DB persistence for this run
--save-db-sdExplicitly enable DB persistence (on by default)
--shell-shOpen the interactive audit shell
--health-check-hcVerify connectivity and API key status
--update-upUpdate Subdominator to the latest release
--release-releaseShow release notes for the latest version
--verbose-vEnable debug logging
--no-color-ncDisable colored output

DB persistence is enabled by default. Every run saves findings to the local SQLite database automatically. Use --no-db to skip persistence for a specific run, or --db-path to 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

CommandDescription
domainsList 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
resourcesList resource catalog with auth markers
configShow active config and database paths
updateUpdate Subdominator to the latest version
releaseShow release notes for the latest version
clearClear the terminal
exit / quitExit 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 crtsh provider internally queries the public crt.sh certificate transparency database over a direct PostgreSQL connection (using asyncpg). 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

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 --all or -ir <name>.

Free (no auth)

NameURLNotes
abuseipdbhttps://abuseipdb.com/
anubishttps://jldc.me/anubis
commoncrawlhttps://index.commoncrawl.org/Slow, large dataset
crtshhttps://crt.shCertificate Transparency
cyfarehttps://cyfare.net/
digitorushttps://www.digitorus.com/
hackertargethttps://hackertarget.com/
hudsonrockhttps://cavalier.hudsonrock.com/
mysslhttps://myssl.com
racenthttps://face.racent.com/
rapiddnshttps://rapiddns.io/
reconcloudhttps://recon.cloud/
riddlerhttps://riddler.io/
shrewdeyehttps://shrewdeye.app/api
sitedossierhttps://www.sitedossier.com/
shodanxhttps://github.com/RevoltSecurities/Shodanx
thchttps://thc.org/
threatcrowdhttps://threatcrowd.org/
threatminerhttps://www.threatminer.org/
waybackarchivehttps://archive.org/waybackVery slow

Optional API key

NameURLNotes
alienvaulthttps://otx.alienvault.comMore results with key
reconeerhttps://www.reconeer.com/More results with key
submdhttps://api.sub.md/More results with key

Requires API key

NameURLAuth notes
argosdnshttps://www.argosdns.ioAPI key
arpsyndicatehttps://www.arpsyndicate.io/pricing.htmlAPI key
bevigilhttps://bevigil.com/loginAPI key
binaryedgehttps://binaryedge.io/API key
bufferoverhttps://tls.bufferover.run/API key
builtwithhttps://api.builtwith.com/domain-apiAPI key
c99https://subdomainfinder.c99.nl/API key
censyshttps://censys.com/id:secret pair
certspotterhttps://sslmate.com/certspotter/API key
chaoshttps://chaos.projectdiscovery.io/API key
chinazhttp://my.chinaz.com/ChinazAPI/DataCenter/MyDataApiAPI key
coderoghttps://rapidapi.com/coderog-coderog-default/api/subdomain-finder5/pricingRapidAPI key (alias: rapidapi)
digitalyamahttps://digitalyama.com/API key
dnsdbhttps://api.dnsdb.infoAPI key
dnsdumpsterhttps://dnsdumpster.com/API key
domainsprojecthttps://domainsproject.org/username:password pair
domscanhttps://domscan.netAPI key
dnsrepohttps://dnsarchive.net/access_token:api_key pair
driftnethttps://driftnet.io/API key
facebookhttps://developers.facebook.com/App ID + Secret
fofahttps://en.fofa.info/API key
fullhunthttps://fullhunt.io/API key
githubhttps://github.com/Personal Access Token
googlehttps://programmablesearchengine.google.com/controlpanel/createcx:key pair
huntermaphttps://hunter.how/API key
intelxhttps://intelx.io/host:key pair (e.g. 2.intelx.io:YOUR_KEY)
leakixhttps://leakix.net/API key
merklemaphttps://www.merklemap.com/API key
netlashttps://netlas.io/API key
odinhttps://odin.io/API key
onyphehttps://www.onyphe.io/API key
profundishttps://api.profundis.io/API key
pugreconhttps://pugrecon.com/API key
quakehttps://quake.360.cn/API key
rapidapihttps://rapidapi.com/hubAPI key (shared by coderog, rapidfinder, rapidscan)
rapidfinderhttps://rapidapi.com/Glavier/api/subdomain-finder3/pricingRapidAPI key (alias: rapidapi)
rapidscanhttps://rapidapi.com/sedrakpc/api/subdomain-scan1/pricingRapidAPI key (alias: rapidapi)
redhuntlabshttps://devportal.redhuntlabs.com/endpoint_url:api_key pair
robtexhttps://proapi.robtex.com/API key
rsecloudhttps://rsecloud.com/searchAPI key
securitytrailshttps://securitytrails.com/API key
shodanhttps://shodan.io/API key
threatbookhttps://threatbook.cn/API key
trickesthttps://trickest.io/API key
urlscanhttps://urlscan.io/API key
virustotalhttps://virustotal.com/API key
whoisfreakshttps://whoisfreaks.com/API key
whoisxmlhttps://whoisxmlapi.com/API key (alias: whoisxmlapi)
windvanehttps://windvane.lichoin.com/API key
zoomeyeapihttps://www.zoomeye.hk/host:key pair (alias: zoomeye)

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 (73 entries)
│   ├── registry.py   # ResourceRegistry + DEFAULT_DISABLED_RESOURCES
│   └── providers/    # 73 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.