If there is one thing I have learned from bug bounty hunting, it is that the reconnaissance phase makes or breaks your entire engagement. You can be the best exploit developer in the world, but if you missed the one subdomain that hosts a forgotten staging environment with an exposed admin panel, you will never find that critical vulnerability. Recon is not optional — it is everything.
Why Recon Matters
Every bounty program has a defined scope. That scope tells you which domains, subdomains, and endpoints you are allowed to test. But here is the reality: the scope is rarely exhaustive. Companies often forget about old subdomains, staging servers, or acquired assets that still resolve to their infrastructure. Your job during recon is to find every single asset the company owns within the scope boundaries — and sometimes a little beyond.
More attack surface means more potential vulnerabilities. A single forgotten subdomain running an outdated version of WordPress or an unauthenticated Grafana dashboard can be your ticket to a critical finding. I have lost count of how many times my highest-paying bounties came from something I found during recon, not during active testing.
Subdomain Enumeration
Subdomain enumeration is the foundation of recon. You want to collect every DNS record associated with your target. I use a layered approach combining passive and active techniques.
Passive enumeration relies on public data sources — certificate transparency logs (crt.sh), search engines, DNS dumpster, and services like SecurityTrails. Tools like amass and subfinder automate this process. I run subfinder first because it is fast and hits 40+ sources out of the box, then feed the results into amass for deeper passive enumeration.
Active enumeration involves brute-forcing subdomains using a wordlist. Tools like ffuf, gobuster, and massdns excel here. I use the best-dns-wordlist.txt from the SecLists project and run massdns against the resolved domains. The key is to start with a large, high-quality wordlist and filter results through httpx to confirm which subdomains are actually serving HTTP traffic.
subfinder -d target.com -o subdomains.txt
amass enum -passive -d target.com -config config.ini
massdns -r resolvers.txt -t A -o S -w massdns_output.txt subdomains.txt
cat massdns_output.txt | awk "{print \$1}" | sort -u | httpx -o live_hosts.txtThe output from httpx gives you a clean list of live web applications. But do not stop there — take each live host and probe deeper.
Tech Stack Fingerprinting
Knowing what technology a target runs is half the battle. If you know a site runs Apache 2.4.49, you can immediately check for CVE-2021-41773 (path traversal). If it runs a specific version of WordPress, you can cross-reference known CVEs.
I use whatweb and wappalyzer for quick initial fingerprinting, then feed everything into nuclei for automated template-based scanning. Nuclei has thousands of templates covering CVEs, misconfigurations, and exposed panels. Running it against your entire asset list after recon is one of the fastest ways to find low-hanging fruit.
whatweb -i live_hosts.txt --aggression 3
nuclei -l live_hosts.txt -t ~/nuclei-templates/ -severity critical,high,medium -o nuclei_results.txtContent Discovery
Once you have confirmed live hosts and know their tech stack, the next step is directory and file brute-forcing. I run ffuf with multiple wordlists depending on the target type. For generic web apps, I use the common.txt and directory-list-2.3-medium.txt wordlists from SecLists. For API endpoints, I use the API-specific wordlists.
ffuf -u https://target.com/FUZZ -w /usr/share/seclists/Discovery/Web-Content/common.txt -o ffuf_common.json
ffuf -u https://api.target.com/FUZZ -w /usr/share/seclists/Discovery/Web-Content/api.txt -o ffuf_api.jsonParam mining is another critical part of content discovery. I use paramspider and ffuf parameter brute-forcing to find hidden or undocumented parameters. Sometimes an application ignores parameters it does not recognize, and those hidden parameters can lead to IDOR or SQL injection.
Organizing Your Findings
Recon generates a lot of data. Subdomains, IP addresses, open ports, HTTP responses, screenshots, JavaScript files, and more. Without proper organization, you will drown in output.
I use a combination of tools. I organize everything per-target in a directory structure: recon/, screenshots/, js-files/, and findings/. I take screenshots of every live page using gowitness or eyewitness — having a visual reference helps you remember what each subdomain does months later. I collect all JavaScript files and analyze them for API endpoints, API keys, and internal paths using linkfinder and jsubfinder.
gowitness file -f live_hosts.txt --destination screenshots/
cat live_hosts.txt | subjs | sort -u > js_urls.txt
cat js_urls.txt | while read url; do linkfinder -i "$url" -o cli; doneSuggested Recon Workflow
Here is the workflow I follow on every single target. It is not the only way to do recon, but it works consistently:
- Passive recon: subfinder, amass (passive), crt.sh, SecurityTrails
- Active recon: massdns DNS brute-force
- Live host filtering: httpx or httprobe
- Port scanning: naabu or rustscan on found IPs
- Screenshots: gowitness for visual context
- Tech fingerprinting: whatweb, webanalyze, nuclei
- Content discovery: ffuf directory + parameter brute-force
- JavaScript analysis: subjs, linkfinder, jsubfinder
- Vulnerability scanning: nuclei template scanning
- Manual review: Burp Suite, browser dev tools, manual testing
The last step is the most important. Automated tools find the obvious stuff, but manual review finds the creative vulnerabilities that make you stand out as a hunter. Once you have your recon data organized, export everything to Burp Suite and start manually exploring each endpoint.
Recon is not a one-time phase. Every time you find something interesting — a new subdomain, a hidden parameter, a JS endpoint — it feeds back into your recon process. Treat it as a cycle, not a step. The deeper you dig in recon, the less you have to guess during exploitation.
