SUBX — Subdomain Recon Framework
A fast, async subdomain enumeration and asset management toolkit for security researchers, pentesters, and bug bounty hunters.
SUBX pulls subdomains from 12 passive sources (Shodan, VirusTotal, Censys, crt.sh, Chaos, etc.), filters them against your scope, stores everything in a database, and optionally probes for HTTP liveness with httpx. It's built to fit into real-world recon workflows without getting in the way.
How it works
┌─────────────────────────────────┐
│ CLI │
└────────────────┬────────────────┘
│
▼
┌─────────────────────────────────┐
│ Services Layer │
└──────┬───────────────────┬──────┘
│ │
▼ ▼
┌──────────────┐ ┌──────────────┐
│PluginManager │ │ ToolManager │
└──────┬───────┘ └──────┬───────┘
│ │
▼ ▼
┌──────────────┐ ┌──────────────┐
│ Passive APIs │ │ Active Tools │
│ (12 sources) │ │ (httpx) │
└──────────────┘ └──────────────┘
Plugins run concurrently via asyncio. Results are deduplicated, scope-filtered, and persisted with first_seen / last_seen timestamps so you can track changes over time.
What's included
- Async everything — all API calls run concurrently, not sequentially
- Plugin auto-discovery — drop a
.pyfile inplugins/and it's loaded automatically - Scope enforcement — in-scope / out-of-scope filtering from your config
- Persistent storage — SQLite by default, PostgreSQL supported natively
- HTTP probing — built-in httpx integration for liveness, status codes, titles, and tech detection
- Historical tracking —
first_seen,last_seen, andlast_seen_alivetimestamps - Project export — auto-generated
recon/directories withsubdomains.txt,alive.txt,dead.txt, etc. - Cross-platform — works on Linux, macOS, and Windows
- Live progress — real-time streaming of discovered subdomains during enumeration
Passive Sources
| Source | API Key Required | Config Key |
|---|---|---|
| AlienVault OTX | Yes | OTX_API |
| AnubisDB | No | — |
| BeVigil | Yes | BEVIGIL_API |
| BGP Tools | No | — |
| Censys | Yes | CENSYS_API |
| Chaos (ProjectDiscovery) | Yes | CHAOS_API |
| crt.sh | No | — |
| HackerTarget | No | — |
| Shodan | Yes | SHODAN_API |
| urlscan.io | Yes | URLSCAN_API |
| ViewDNS | Yes | VIEWDNS_API |
| VirusTotal | Yes | VIRUSTOTAL_API |
Installation
From PyPI (recommended)
pip install subx-recon
From source
git clone https://github.com/RiadhBenlamine/SubX.git
cd SubX
pip install -e .
Or with uv:
git clone https://github.com/RiadhBenlamine/SubX.git
cd SubX
uv sync
Debian/Ubuntu/Kali (.deb)
Download the .deb from the latest release and install:
sudo apt install ./subx_2.1.0-1_all.deb
Requirements: Python >= 3.10
Setup
Create a config.yaml (there's a sample in config_samples/):
scope:
- example.com
- target.org
out_of_scope:
- testing.example.com
# Leave blank to run all plugins, or list specific ones
sources:
- ShodanPlugin
- CrtshPlugin
api_keys:
SHODAN_API: "your-key-here"
VIRUSTOTAL_API: "your-key-here"
OTX_API: "your-key-here"
URLSCAN_API: "your-key-here"
CHAOS_API: "your-key-here"
BEVIGIL_API: "your-key-here"
VIEWDNS_API: "your-key-here"
CENSYS_API: "your-key-here"
You can also keep API keys in ~/.config/subx/.env (e.g. SHODAN_API=your-key). Config file values take priority.
Usage
subx [COMMAND] [OPTIONS]
# From source:
uv run python main.py [COMMAND] [OPTIONS]
Enumerate subdomains
subx enum -c config.yaml
Runs all configured plugins against your scope targets. Results are saved to the database by default. Subdomains stream to your terminal in real-time as each plugin returns results.
Options:
-c,--config— path to your config file (required)--save/--no-save— toggle database persistence (default: save)--project,-p— auto-export project directory after scan--debug— verbose logging
Probe for HTTP liveness
subx http-probe -d example.com
Reads subdomains from the database, runs httpx with tech detection, and updates records with status codes, titles, technologies, and timestamps.
Options:
-d,--domain— target domain (required)-oN <file>— save alive subdomains, one per line-oX '<sep>:<file>'— custom separator output (e.g.';:alive.txt')-oT <file>— save subdomains with tech stack (e.g.app.example.com [Nginx, React])
Query the database
# Show all tracked targets
subx db
# List subdomains for a target
subx db -d example.com
# Show web details (alive status, HTTP code, title, tech)
subx db -d example.com --web
# Filter by plugin source
subx db -d example.com --filter-plugin ShodanPlugin
# Filter by technology
subx db -d example.com --filter-tech Nginx
# Only alive / only dead
subx db -d example.com --alive
subx db -d example.com --down --web
# Subdomains discovered after a date
subx db -d example.com --new-since 2025-01-01
# Raw SQL query
subx db -C "SELECT subdomain, status_code, tech FROM subx_subdomain WHERE target='example.com' AND alive=1"
# Delete all records for a target
subx db -d example.com --delete
# Export to file
subx db -d example.com --alive -oN live_subs.txt
Export project directories
subx project -d example.com
Creates a structured recon folder:
projects/
└── example.com/
└── recon/
├── subdomains.txt
├── alive.txt
├── dead.txt
├── techs.txt
├── status.txt
├── ips.txt
└── sources.txt
You can also pass --project / -p to enum, http-probe, or db commands to auto-generate this after any operation.
Initialize PostgreSQL
# Interactive setup
subx init-db
# Non-interactive
subx init-db -H 127.0.0.1 -u postgres -P "mypassword" -d subx
This creates the database, sets up schema tables, and saves the connection to ~/.config/subx/config.yaml so all future commands use PostgreSQL.
Import from SQLite
# Into your configured database
subx import-sqlite subx.db
# With explicit target
subx import-sqlite subx.db -t "postgresql+asyncpg://user:pass@localhost:5432/subx"
Migrates all targets, subdomains, probe results, timestamps, and source linkages.
Database migrations
subx dev-migrate
Compares your database schema against current models and adds any missing columns. Creates a backup first by default (skip with --no-backup).
PostgreSQL support
SUBX works with SQLite out of the box. To switch to PostgreSQL, either:
- Run
subx init-db(recommended), or - Set the
DATABASE_URLenvironment variable:
export DATABASE_URL="postgresql+asyncpg://user:password@localhost:5432/subx"
All commands work identically on both backends.
Release automation
# Bump patch (2.0.19 → 2.0.20)
python scripts/release.py patch
# Bump minor (2.0.19 → 2.1.0)
python scripts/release.py minor
# Set exact version
python scripts/release.py 2.1.0
Handles version bumping, tests, wheel/sdist/deb builds, PyPI upload, git tagging, and GitHub push.
Contributing
See DEV_DOCS.md for the architecture guide, API reference, layering rules, and how to add new plugins or tool wrappers.
License
MIT — see LICENSE for details.
Metadata
Release files for subx-recon 2.1.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| subx_recon-2.1.1.tar.gz | 56.3 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| subx_recon-2.1.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 135.0 kB
Release files / subx_recon-2.1.1.tar.gz
| Download URL | subx_recon-2.1.1.tar.gz |
|---|---|
| Size | 56.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
e9289c67dae0334e9d6e0c002fa156c3c5d207e3bb5c840f6db38d75421c3920
|
|
BLAKE2b-256 checksum How to use checksums |
2ccfe64035bcb0f5cef112df6e86febd6eb053d977088ff0573e9d01f56aee0b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.14.6
|
Release files / subx_recon-2.1.1-py3-none-any.whl
| Download URL | subx_recon-2.1.1-py3-none-any.whl |
|---|---|
| Size | 78.7 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
9f35f83ea318f618a54e057c8e7432664b3efd02863c960c57fff82881b95390
|
|
BLAKE2b-256 checksum How to use checksums |
1bbb367979495a3094380f821a70d915b36c497a5771098e36a4df3c54c81a7a
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.14.6
|