subfinder
Passive subdomain enumeration across dozens of public sources with provider keys, match/filter rules and JSONL output. Use when scoping a domain, expanding a host list, or feeding httpx and dnsx. Not
Files1
View on GitHubSKILL.mdskills/subfinder/SKILL.md
GitHubSubfinder
Subfinder collects subdomains from passive sources: certificate transparency logs, search engines, DNS datasets, threat-intel APIs and archive crawls. It sends no traffic to the target itself, so it is the safe first step of external reconnaissance. The quality of the result is directly proportional to how many provider API keys you have configured.
When to use
| Goal | Command shape |
|---|---|
| Initial host list for one domain | subfinder -d target.test -silent |
| Many domains from a scope file | subfinder -dL domains.txt -silent -oD out/ |
| Exhaustive pass with every source | subfinder -d target.test -all -silent |
| Only sources that return sub-subdomains | subfinder -d target.test -recursive -silent |
| Keep environment hosts, drop marketing | subfinder -d target.test -match-regex '^dev\.' |
| Machine-readable output | subfinder -d target.test -oJ -silent |
| Only hosts that currently resolve | subfinder -d target.test -nW -silent |
| Feed a probe pipeline | subfinder ... -silent | anew subs.txt | httpx -silent |
Use it before any active tool. Do not use it to brute force names (that is dnsx with /opt/wordlists/subs-20k.txt) or to decide whether a host is alive over HTTP (that is httpx).
Prerequisites
- Binary at
/opt/tools/subfinder;subfinder -versionprints[INF] Current Version: v2.17.0on this host. - Config directory
/root/.config/subfinderis created on first run. Effective config:config.yaml; provider keys:provider-config.yaml. subfinder -lslists 54 sources.*means the source requires a key,~means a key improves results but is optional.- No wordlist is needed. Enumeration is passive.
The provider file is a YAML map of source name to a list of credentials. On a fresh host every entry is an empty list:
# shape only -- never commit real keys
github:
- ghp_EXAMPLE
shodan:
- FAKEKEY0000000000000000000000000000
Some providers expect two values joined by : inside one list entry; check the provider's own console before filling it. Keep the file at mode 600.
Why keys matter: keyless sources (crtsh, commoncrawl, waybackarchive, rapiddns, anubis, thc, sitedossier) return a baseline, but * sources silently return nothing without a token. Keys also raise per-source quotas; -rls shows the built-in defaults such as github=30/m and virustotal=4/m. An invalid key usually produces a source error in verbose mode, not a hard failure.
Core invocations
# 1. baseline, passive, banner-free
subfinder -d target.test -silent
# 2. exhaustive: every source, slow and quota-hungry
subfinder -d target.test -all -silent -o all.txt
# 3. bulk scope file, one output directory per domain
subfinder -dL domains.txt -silent -oD out/
# 4. restrict to sources that can return deeper names (not a brute force)
subfinder -d target.test -recursive -silent
# 5. pin the source set when a provider is down or out of quota
subfinder -d target.test -s crtsh,commoncrawl,waybackarchive,rapiddns -silent
# 6. exclude noisy or slow providers
subfinder -d target.test -es alienvault,zoomeyeapi,robtex -silent
# 7. keep only likely-interesting names
subfinder -d target.test -match-regex '^(dev|stg|uat|admin|api)\.' -silent
# 8. drop CDN and parked-name noise
subfinder -d target.test -filter-regex 'cdn|akamai|cloudfront' -silent
# 9. JSONL, then inspect the actual keys before writing jq filters
subfinder -d target.test -oJ -silent | tee subs.jsonl
jq -r 'keys[]' subs.jsonl | sort -u
# 10. active-only: adds DNS resolution on top of the passive result
subfinder -d target.test -nW -silent
# 11. conservative pace for shared or rate-limited keys
subfinder -d target.test -rl 20 -t 5 -timeout 20 -max-time 5 -silent
# 12. dedupe across runs and feed the prober in one pipe
subfinder -d target.test -silent | anew subs.txt | httpx -silent -sc -title
# 13. per-domain files for a large scope
subfinder -dL domains.txt -oD out/ -silent
# 14. alternate provider file for a second key set
subfinder -d target.test -pc ./provider-config.yaml -silent
# 15. verify which sources exist on this build
subfinder -ls | sed -n '1,25p'
Flags that matter
| Flag | Effect | Note |
|---|---|---|
-d |
domain(s) to enumerate | repeatable, also string[] |
-dL |
file of domains | pair with -oD |
-all |
use every source | slow; burns quotas |
-recursive |
restrict to recursive-capable sources | does not recurse itself |
-s / -es |
include / exclude sources | comma separated |
-m / -f |
string match / filter | not regex; files accepted |
-match-regex / -filter-regex |
regex include / exclude | use these for patterns |
-nW |
only active (resolving) names | performs DNS lookups |
-oJ |
JSONL output | one object per host |
-o / -oD |
single file / directory | -oD is for -dL |
-silent |
hosts only | suppress banner and logs |
-rl / -t |
global requests/sec / concurrency | lower on shared keys |
-timeout / -max-time |
per-request seconds / total minutes | defaults 30 and 10 |
-pc |
provider config path | default ~/.config/subfinder/provider-config.yaml |
-r / -rL |
custom DNS resolvers | needed for -nW behind split DNS |
-ip / -exclude-ip |
include / strip IPs | -ip requires active mode |
-duc |
disable update check | avoids an update-check request per run |
-stats |
per-source statistics | use when a source looks empty |
Workflow
- Confirm scope and authorization. Enumerate only domains you may test; passive results can include unrelated third parties.
- Run the keyless baseline with
-s crtsh,commoncrawl,waybackarchive,rapiddnsfor a fast first picture. - Add keys, then run
-all. Compare counts; a large jump means keyed sources are contributing. - Normalize. Lowercase, strip
*.wildcards and trailing dots, thensort -u. Keep the raw file untouched. - Resolve.
dnsx -l subs.txt -silentorsubfinder -nWseparates live names from stale records. - Hand off. Feed live names to httpx, then probe paths and JS. Re-run subfinder later; certificate transparency grows continuously.
OPSEC and telemetry
- Queries go to passive providers, not the target, so the target's DNS logs stay clean. Providers still log your source IP, API key and the domain queried.
-nW,-ipand custom resolvers perform DNS lookups. Those are visible to authoritative DNS and to the resolver operator.-allcan exhaust provider quotas and get keys temporarily banned. Prefer a pinned-slist during a time-boxed engagement.- Without
-duc, subfinder performs an update check over the network. Disable it on engagements that forbid unexpected egress. - Results may include expired, parked, wildcard or transferable names. Verify ownership before scanning; an out-of-scope hostname is still out of scope.
- Store raw output with a timestamp. Passive data changes daily and is your evidence of what was known when.
Failure modes
| Symptom | Cause | Fix |
|---|---|---|
| Zero or near-zero results | all keyed sources skipped, keys invalid | run -v, add -s crtsh, check provider-config.yaml |
429 or source errors in verbose output |
provider quota | lower -rl, wait, or exclude that source |
Only a few names with -recursive |
flag restricts the source set | drop it or add -all |
-oD writes nothing |
used without -dL or directory not writable |
use -o for one domain, fix permissions |
Output full of *.target.test |
wildcard records from passive data | strip in post-processing; do not scan wildcards blindly |
| Names resolve to a CDN | wildcard DNS or hosted service | check CNAME with dnsx -cname before probing |
no such host / resolver timeouts |
broken local resolver or filtered egress | pass -r 1.1.1.1 or -rL resolvers.txt |
| Same host listed twice | multiple sources | dedupe with anew or sort -u |
| Config ignored | -pc path typo or unreadable file |
print the path and test with ls -l |
Verification
subfinder -version
# [INF] Current Version: v2.17.0
subfinder -ls | head -5
# banner, then "Current list of available sources"
subfinder -d example.com -s crtsh -silent | head
# one hostname per line, no log lines
Check that -silent output is clean enough for a pipe:
subfinder -d example.com -s crtsh -silent | grep -c '^[a-z0-9._-]*example\.com$'
Keep the exact command, timestamp, source list and raw output as evidence. If a count looks wrong, re-run with -v and -stats before concluding the source is dead.
Related skills
- httpx to turn names into live HTTP services
- jsluice once probing reveals JavaScript
- redteam-toolchain for binary paths and host layout
- toolchain-router when another discovery tool fits better