October 29, 2026
6 Methods of Automating the Reconnaissance Method of Bug Bounty
A copy and paste bug bounty recon pipeline, from finding hidden subdomains to scanning for real vulnerabilities, and the one script that…

By Devansh Patel
5 min read
A copy and paste bug bounty recon pipeline, from finding hidden subdomains to scanning for real vulnerabilities, and the one script that ties it all together.
A Secret about Bug Bounty
The quickest hackers can earn the most money. When a new subdomain is created for a company at 2 AM then whoever finds it first will have the bug and everyone else will have a dupe.
This can't be done by hand so I created a recon pipeline using 6 free open source tools. They were all linked together via one Bash script which I would run automatically every few hours.
All the screen shots are taken from my own Kali terminal and you have try them as well.
The One Rule that Keep You of the Trouble
When conducting scans make sure you are only scanning systems you have permission to scan. This can either be through an active bug bounty and the domain is within scope, or a practice environment. In this article I will be using a series of deliberately vulnerable practice websites from Acunetix (vulnweb.com).
Before beginning to run any scans make sure you're aware of the rules. A lot of programs completely block automated tools, many will have rate limiting and some will require you to include a header with your username. You may be banned if you aren't following these rules.
Setup Once
sudo apt update && sudo apt install -y golang jq
go install -v github.com/projectdiscovery/subfinder/v2/cmd/subfinder@latest
go install -v github.com/projectdiscovery/httpx/cmd/httpx@latest
go install -v github.com/projectdiscovery/katana/cmd/katana@latest
go install -v github.com/projectdiscovery/nuclei/v3/cmd/nuclei@latest
go install -v github.com/lc/gau/v2/cmd/gau@latest
go install -v github.com/tomnomnom/anew@latest
echo 'export PATH="$HOME/go/bin:$PATH"' >> ~/.zshrc && source ~/.zshrcsudo apt update && sudo apt install -y golang jq
go install -v github.com/projectdiscovery/subfinder/v2/cmd/subfinder@latest
go install -v github.com/projectdiscovery/httpx/cmd/httpx@latest
go install -v github.com/projectdiscovery/katana/cmd/katana@latest
go install -v github.com/projectdiscovery/nuclei/v3/cmd/nuclei@latest
go install -v github.com/lc/gau/v2/cmd/gau@latest
go install -v github.com/tomnomnom/anew@latest
echo 'export PATH="$HOME/go/bin:$PATH"' >> ~/.zshrc && source ~/.zshrcThen make a folder for your target
T=vulnweb.com
mkdir -p ~/recon/$T && cd ~/recon/$TT=vulnweb.com
mkdir -p ~/recon/$T && cd ~/recon/$TInteresting Fact to Note :- There is already a program called httpx on Kali (same name as the python tool). Adding ~/go/bin to the start of the PATH will ensure the right version from ProjectDiscovery is being used. You can verify this by typing httpx -version. This will cause confusion for almost all beginners due to the naming conflict.
1. Finding every Subdomain without Touching the Target
subfinder -d $T -all -silent | anew subs.txt
curl -s "https://crt.sh/?q=%25.$T&output=json" | jq -r '.[].name_value' | sed 's/^\*\.//' | sort -u | anew subs.txt
wc -l subs.txtsubfinder -d $T -all -silent | anew subs.txt
curl -s "https://crt.sh/?q=%25.$T&output=json" | jq -r '.[].name_value' | sed 's/^\*\.//' | sort -u | anew subs.txt
wc -l subs.txtWhat it would do :- It queries many sources to find out what subdomains they know. The second line is querying crt.sh which is an SSL certificate search engine. Both of these are dumped into subs.txt.
What anew it does :- It will only add the lines which are not already there and will only show the ones it added. This is the core of the entire pipeline.
Interesting Fact about it :- All HTTPS certificates are recorded in public Certificate Transparency logs. As soon as a certificate has been issued for a subdomain of a company, it is no longer possible to hide it. If you encounter a timeout using crt.sh then simply try again. It's a free service so can be busy!
2. Finding which Subdomains are Actually Alive
httpx -l subs.txt -silent -rl 20 | anew live.txt
httpx -l live.txt -sc -title -td -silent -rl 20httpx -l subs.txt -silent -rl 20 | anew live.txt
httpx -l live.txt -sc -title -td -silent -rl 20What it would do :- Most subdomains will be blank, and we can check them all with this to leave just those that actually exist. On the second line we can see what status code they have, along with the page title. We can also see what technology they are using for example PHP, Nginx and WordPress.
What is the fix :- The -rl 20 limits it to 20 requests per second. Always set a rate limit, so you never hammer a target.
Interesting Fact :- The page titles are pure gold. Words like "staging", "admin", "dev" or "test" in a title often point to forgotten systems with weaker security than the main site.
3. Dig Up the Old URLs the Internet Remembers
echo $T | gau --subs | anew urls.txt
wc -l urls.txt
grep -Ei '\.(php|js|json|bak|sql|zip|env|config)(\?|$)' urls.txt | sort -u | head -20
grep '=' urls.txt | sort -u | head -20echo $T | gau --subs | anew urls.txt
wc -l urls.txt
grep -Ei '\.(php|js|json|bak|sql|zip|env|config)(\?|$)' urls.txt | sort -u | head -20
grep '=' urls.txt | sort -u | head -20What it does: gau pulls every URL that the Wayback Machine and other archives have ever seen for the target. The first grep finds interesting file types. The second finds URLs with parameters, which is where bugs like XSS and SQL Injection usually live.
Interesting fact: The site may have deleted a page years ago, but the archive still remembers it. Old endpoints that were removed from the menu but never removed from the server are some of the most common bounty wins.
4. Crawl the Real Websites and Scan their Javascript
katana -list live.txt -d 2 -jc -silent -rl 20 | anew crawl.txt
wc -l crawl.txt
grep -Ei '\.js(\?|$)' crawl.txt | sort -u | head -10katana -list live.txt -d 2 -jc -silent -rl 20 | anew crawl.txt
wc -l crawl.txt
grep -Ei '\.js(\?|$)' crawl.txt | sort -u | head -10What it would do: katana visits the live sites like a browser and follows links two levels deep. The -jc option also reads JavaScript files and pulls out any paths hidden inside them.
Interesting Fact: Modern websites ship most of their logic as JavaScript, which means they often ship a map of their own API to every visitor. Hunters read JS files for hidden endpoints, old API versions, and sometimes even leaked keys.
5. Scan the Real World Vulnerablilities with the Nuclei
nuclei -update-templates
nuclei -l live.txt -s low,medium,high,critical -rl 20 -silent | anew findings.txtnuclei -update-templates
nuclei -l live.txt -s low,medium,high,critical -rl 20 -silent | anew findings.txt
What it wuld do :- Nuclei will perform thousands of prewritten tests (templates) against every host. Each test will check for a specific vulnerability such as exposed configuration files, common CVE and misconfigured servers. The results will show what severity the issue is.
How it will work :- Never simply copy and paste any findings from Nuclei into your report. Always go to the URL and ensure the issue exists. Every day there are programs that will dismiss scanner findings due to them not being verified. Having multiple low quality reports can affect your reputation.
Interesting Fact to Note :- Templates are created by the community. Often when a large new CVE comes out a new template will be added within days, sometimes hours. Keeping your templates up to date before scanning means you will find new bugs before anyone else.
6. Wire it Up Together and Let it Run Forever
This is where the real magic happens. One script, and it only alerts you about things that are new since the last run
cat > ~/recon.sh <<'EOF'
#!/usr/bin/env bash
set -euo pipefail
T="${1:?usage: recon.sh domain}"
D="$HOME/recon/$T"; mkdir -p "$D"; cd "$D"
log() { printf '\033[1;36m[%s]\033[0m %s\n' "$(date +%H:%M:%S)" "$*"; }
log "Hunting subdomains for $T"
subfinder -d "$T" -all -silent | anew subs.txt > new_subs.txt
log "New subdomains: $(wc -l < new_subs.txt)"
if [ -s new_subs.txt ]; then
httpx -l new_subs.txt -silent -rl 20 | anew live.txt > new_live.txt
log "New live hosts: $(wc -l < new_live.txt)"
if [ -s new_live.txt ]; then
nuclei -l new_live.txt -s medium,high,critical -rl 20 -silent | anew findings.txt > new_findings.txt
log "New findings: $(wc -l < new_findings.txt)"
if [ -s new_findings.txt ]; then
notify-send "Recon: new findings on $T" "$(head -3 new_findings.txt)" 2>/dev/null || true
fi
fi
fi
log "Done. Everything is saved in $D"
EOF
mv ~/recon/$T ~/recon/${T}_manual
bash ~/recon.sh $T
bash ~/recon.sh $Tcat > ~/recon.sh <<'EOF'
#!/usr/bin/env bash
set -euo pipefail
T="${1:?usage: recon.sh domain}"
D="$HOME/recon/$T"; mkdir -p "$D"; cd "$D"
log() { printf '\033[1;36m[%s]\033[0m %s\n' "$(date +%H:%M:%S)" "$*"; }
log "Hunting subdomains for $T"
subfinder -d "$T" -all -silent | anew subs.txt > new_subs.txt
log "New subdomains: $(wc -l < new_subs.txt)"
if [ -s new_subs.txt ]; then
httpx -l new_subs.txt -silent -rl 20 | anew live.txt > new_live.txt
log "New live hosts: $(wc -l < new_live.txt)"
if [ -s new_live.txt ]; then
nuclei -l new_live.txt -s medium,high,critical -rl 20 -silent | anew findings.txt > new_findings.txt
log "New findings: $(wc -l < new_findings.txt)"
if [ -s new_findings.txt ]; then
notify-send "Recon: new findings on $T" "$(head -3 new_findings.txt)" 2>/dev/null || true
fi
fi
fi
log "Done. Everything is saved in $D"
EOF
mv ~/recon/$T ~/recon/${T}_manual
bash ~/recon.sh $T
bash ~/recon.sh $TThe mv line keeps your results from steps 1 to 5 safe in another folder, so the script starts fresh and you can watch it find everything on its first run.
You can see the second run gives 0 new results as anew will keep track of the information it has already seen. This means that you will only be notified when there IS an actual change.
Run the script every 6 hours automatically:
(crontab -l 2>/dev/null; echo "PATH=$HOME/go/bin:/usr/local/bin:/usr/bin:/bin"; echo "0 */6 * * * /usr/bin/bash $HOME/recon.sh vulnweb.com >> $HOME/recon/cron.log 2>&1") | crontab -
crontab -l(crontab -l 2>/dev/null; echo "PATH=$HOME/go/bin:/usr/local/bin:/usr/bin:/bin"; echo "0 */6 * * * /usr/bin/bash $HOME/recon.sh vulnweb.com >> $HOME/recon/cron.log 2>&1") | crontab -
crontab -lFix: That PATH line matters. Cron starts with an almost empty PATH, so without it, cron cannot find any of your Go tools and the script fails silently.
Fun fact: This is the idea behind what hunters call continuous recon. The main domain of a big company has been tested by thousands of people. A subdomain that appeared an hour ago has been tested by nobody. Your script just made sure you are first.