FFUF surfaces what subdomain enumeration and crawlers miss — hidden directories, backup files, admin panels, API endpoints, and virtual hosts that exist on a server but never appear in links or sitemaps. This guide covers how to automate FFUF across multiple targets, chain its output into Nuclei for vulnerability validation, and build content discovery pipelines that run continuously without manual intervention.
Subdomain enumeration gives you the hosts. Live host probing confirms they're running web services. But neither tells you what's actually on those hosts. FFUF fills that gap — it brute-forces paths, parameters, and virtual host headers to surface the content that's present but not linked.
The highest-value targets in any bug bounty scope aren't the main application endpoints you can see. They're the /admin panels that weren't removed, the .env files left in web roots, the /api/v1/internal endpoints that were never deprecated, and the backup archives that someone uploaded once and forgot. FFUF finds all of them.
/admin, /dashboard, /manage, /console — control plane endpoints that weren't removed from production servers.
.env, .git, config.php.bak, database.yml — sensitive files left in web roots during deploys or migrations.
/api/v1/, /api/internal/, /graphql, /rest/ — API surfaces that weren't documented or deprecated properly.
Internal applications running on the same IP as the main site, accessible only via the correct Host header.
Most FFUF guides show the basic -u URL/FUZZ -w wordlist.txt pattern and stop there. Automation requires understanding the filtering and output flags that make FFUF usable at scale — especially across dozens of targets where manual review of every response is impossible.
| Flag | Purpose | Automation Use |
|---|---|---|
| -ac | Auto-calibration — automatically detects and filters baseline response sizes | Essential for multi-host automation. Eliminates manual -fs/-fw tuning per host. |
| -mc | Match HTTP status codes (e.g. 200,301,403) | Use 200,201,204,301,302,307,401,403 to capture both accessible and restricted paths. |
| -fc | Filter HTTP status codes | Use -fc 404 to suppress not-found responses when -ac isn't sufficient. |
| -fs | Filter by response size (bytes) | Run a baseline request first, then filter that exact size to remove identical error pages. |
| -fw | Filter by word count in response | More reliable than -fs on sites where error page sizes vary slightly. |
| -rate | Max requests per second | Set 50-100 for most targets. Reduce to 20-30 on private programs or WAF-protected hosts. |
| -t | Concurrent threads | 40-50 is safe for most targets. Higher = faster but more detection risk. |
| -o / -of | Output file and format (json, csv, md) | Always use -o with -of json for pipeline integration with jq and Nuclei. |
| -H | Custom header | Used for vhost fuzzing: -H 'Host: FUZZ.target.com' and for auth bypass testing. |
| -recursion | Recursive fuzzing on discovered directories | Use with -recursion-depth 2 for deeper discovery. Increases runtime significantly. |
Auto-calibration (-ac) is the single most important flag for automation. Without it, every target requires a manual baseline request to determine what to filter. With it, FFUF automatically sends calibration requests at startup and sets the right filters. Always start with -ac and only add explicit filters if calibration isn't sufficient.
These are production-grade FFUF patterns used in real bug bounty pipelines. Each builds on the previous — start with the one-liner for quick sweeps, use the full script for targets you're actively hunting.
The minimum viable content discovery run. Auto-calibration handles false positive filtering automatically. Output goes to JSON for downstream processing.
ffuf \
-u https://target.com/FUZZ \
-w /opt/homebrew/share/seclists/Discovery/Web-Content/raft-medium-directories.txt \
-ac \
-mc 200,201,204,301,302,307,401,403 \
-t 50 \
-rate 100 \
-o dirs.json \
-of json \
-s
Specifically targets files that developers accidentally leave in web roots. High signal-to-noise ratio — a 200 response on any of these is almost always a real finding worth reporting.
# Target: .env, .git, .bak, config files, archives
ffuf \
-u https://target.com/FUZZ \
-w /opt/homebrew/share/seclists/Discovery/Web-Content/raft-medium-files.txt \
-mc 200,204 \
-ac \
-t 40 \
-rate 60 \
-o backups.json \
-of json \
-s
# Extract findings immediately
jq -r '.results[] | [.status, .length, .url] | @tsv' backups.json
Discovers internal applications running on the same IP as the main site. Particularly effective on corporate scopes where internal tooling (Jenkins, Grafana, internal APIs) runs on the same server but requires a specific Host header. Requires knowing the baseline response size first.
# Step 1: Get baseline size for a non-existent vhost
curl -s -o /dev/null -w "%{size_download}" \
-H "Host: nonexistent12345.target.com" \
https://target.com
# → note the size, use as -fs value below
# Step 2: Fuzz virtual hosts, filter baseline size
ffuf \
-u https://target.com \
-H "Host: FUZZ.target.com" \
-w /opt/homebrew/share/seclists/Discovery/DNS/subdomains-top1million-5000.txt \
-fs 1234 \
-mc 200,301,302,401,403 \
-t 40 \
-rate 80 \
-o vhosts.json \
-of json \
-s
Discovers hidden GET parameters on known endpoints. Useful after directory fuzzing — once you've found an interesting path, parameter fuzzing can reveal additional functionality, internal flags, or debug modes that weren't documented.
# Fuzz GET parameters on a discovered endpoint
ffuf \
-u "https://target.com/api/endpoint?FUZZ=test" \
-w /opt/homebrew/share/seclists/Discovery/Web-Content/burp-parameter-names.txt \
-ac \
-mc 200,201,204 \
-t 30 \
-rate 50 \
-o params.json \
-of json \
-s
# POST parameter fuzzing
ffuf \
-u "https://target.com/api/endpoint" \
-X POST \
-d "FUZZ=test" \
-H "Content-Type: application/x-www-form-urlencoded" \
-w /opt/homebrew/share/seclists/Discovery/Web-Content/burp-parameter-names.txt \
-ac \
-mc 200,201,204 \
-t 30 \
-s
The complete automation script — reads a live-hosts.txt from your subdomain recon pipeline, runs directory + backup fuzzing against each host, then chains discovered URLs into Nuclei for vulnerability validation.
#!/usr/bin/env bash
# PhantomRed — FFUF Multi-Host Content Discovery Pipeline
# Usage: ./ffuf-pipeline.sh live-hosts.txt
# Requires: ffuf, nuclei, jq, seclists
HOSTS="${1:-live-hosts.txt}"
OUT="./ffuf-results/$(date +%Y%m%d_%H%M%S)"
DIRLIST="/opt/homebrew/share/seclists/Discovery/Web-Content/raft-medium-directories.txt"
FILELIST="/opt/homebrew/share/seclists/Discovery/Web-Content/raft-medium-files.txt"
mkdir -p "$OUT"
echo "[*] FFUF pipeline — $(wc -l < $HOSTS) hosts"
while IFS= read -r HOST; do
SAFE=$(echo "$HOST" | sed 's|https\?://||' | tr '/:' '__')
mkdir -p "$OUT/$SAFE"
echo " → $HOST"
# Directory fuzzing
/opt/homebrew/bin/ffuf \
-u "${HOST}/FUZZ" \
-w "$DIRLIST" \
-ac -mc 200,201,204,301,302,307,401,403 \
-t 50 -rate 100 -timeout 10 \
-o "$OUT/$SAFE/dirs.json" -of json -s 2>/dev/null || true
# Backup file detection
/opt/homebrew/bin/ffuf \
-u "${HOST}/FUZZ" \
-w "$FILELIST" \
-mc 200,204 \
-t 30 -rate 50 -timeout 10 \
-o "$OUT/$SAFE/backups.json" -of json -s 2>/dev/null || true
# Extract all discovered URLs
/opt/homebrew/bin/jq -r '.results[].url' \
"$OUT/$SAFE/dirs.json" "$OUT/$SAFE/backups.json" \
2>/dev/null \
>> "$OUT/all-discovered-urls.txt" || true
done < "$HOSTS"
# STAGE 2 — Nuclei validation on discovered endpoints
if [[ -s "$OUT/all-discovered-urls.txt" ]]; then
sort -u "$OUT/all-discovered-urls.txt" -o "$OUT/all-discovered-urls.txt"
echo "[*] Discovered URLs: $(wc -l < $OUT/all-discovered-urls.txt)"
echo "[*] Running Nuclei on discovered endpoints..."
/opt/homebrew/bin/nuclei \
-l "$OUT/all-discovered-urls.txt" \
-t vulnerabilities/,exposures/ \
-severity medium,high,critical \
-rl 30 \
-timeout 10 \
-silent \
-json \
-o "$OUT/nuclei-on-ffuf.json" || true
fi
echo "[✓] Done. Results: $OUT/"
FFUF discovers endpoints. Nuclei validates whether those endpoints are actually vulnerable. Running Nuclei only on FFUF-discovered URLs (rather than the full host list) dramatically reduces scan noise — you're validating real endpoints, not guessing at paths.
The wordlist determines what FFUF finds. Using the wrong wordlist for the wrong target type is the most common reason hunters miss high-value findings. These are the SecLists wordlists that produce the highest signal-to-noise ratio for each use case.
raft-medium-directories.txt — 30k entries, covers most common paths. Start here on every target before moving to larger lists.
raft-medium-files.txt — targets .env, .bak, .sql, config files. High value, low false positive rate.
common-api-endpoints-mazen160.txt — REST and GraphQL endpoint patterns. Use on hosts with detected API frameworks.
burp-parameter-names.txt — 6k common parameter names. Run on interesting endpoints discovered during directory fuzzing.
subdomains-top1million-5000.txt — use as Host header wordlist. Discovers internal apps on shared IPs.
directory-list-2.3-big.txt — 1.2M entries for thorough coverage. Use only on high-value targets with rate limiting.
All wordlists above are from SecLists. Install via Homebrew: brew install seclists — installs to /opt/homebrew/share/seclists/. On Linux: apt install seclists or clone from github.com/danielmiessler/SecLists.
Without auto-calibration, FFUF returns every path that matches your -mc status codes — including generic error pages that return 200. Fix: always start with -ac. If results are still noisy, manually check the baseline response size and add -fs [size].
A wordlist optimized for PHP applications will miss most findings on a Node.js API. Match the wordlist to the detected technology stack. Use httpx -tech-detect output from your recon pipeline to choose the right list — API endpoints for detected frameworks, CMS-specific paths for WordPress/Drupal targets.
Default FFUF concurrency hits targets aggressively. On a list of 50 hosts with no -rate flag, you're sending thousands of requests per second across the program scope. This triggers WAF blocks and program bans. Fix: set -rate 100 as a maximum and reduce to 30-50 on sensitive targets.
Many hunters filter out 403s entirely. This misses a significant finding category — a 403 on /admin or /internal/api confirms the path exists and is access-controlled. That's worth testing for auth bypass. Always include 403 in your -mc and triage separately.
FFUF discovers endpoints — it doesn't validate vulnerability. Most hunters stop at "found /admin" and manually test. The higher-leverage approach: extract all discovered URLs with jq and run them through Nuclei's vulnerabilities/ templates automatically. This turns content discovery into a vulnerability discovery pipeline.
PhantomRed runs FFUF as part of its autonomous offensive security pipeline. After subdomain enumeration and live host probing, the platform automatically selects wordlists based on detected technology stacks — API endpoint lists for detected API frameworks, CMS-specific wordlists for WordPress or Drupal targets, generic directory lists for unknown stacks.
FFUF-discovered endpoints are automatically fed into the Nuclei scan pipeline for vulnerability validation. You see findings organized by endpoint — not raw FFUF output — with severity scoring applied across the full discovery-to-validation chain. See the Recon Workflow Generator to build custom FFUF pipelines for specific target profiles.
FFUF receives the validated live-hosts.txt output from the subdomain recon pipeline — only confirmed web services, no dead hosts.
httpx outputTechnology fingerprints from httpx -tech-detect inform which wordlists run against each host. API hosts get API endpoint lists. CMS hosts get CMS-specific paths.
auto wordlist routingAll three FFUF modes run per host with auto-calibration and rate limiting applied automatically per target.
ffufAll discovered URLs are automatically fed into Nuclei for vulnerability template matching. No manual jq extraction required.
nucleiFindings are deduplicated, severity-scored, and surfaced in your dashboard organized by endpoint — not by tool output order.
phantomred engine-o for JSON output per host, -ac for automatic calibration, and -rate to avoid WAF blocks. Store results in per-host subdirectories for clean organization.raft-medium-directories.txt from SecLists is the best starting point — it covers the most common paths with minimal noise. For backup files, use raft-medium-files.txt. For API endpoints, use common-api-endpoints-mazen160.txt. Install all via: brew install seclists.-fs [size] to surface real vhosts only.-ac (auto-calibration) which automatically detects and filters baseline response sizes. For additional filtering use -fc to filter status codes, -fs to filter by response size, and -fw to filter by word count. Running a manual baseline request first helps identify the correct filter values for a specific target.jq -r '.results[].url' ffuf-output.json > endpoints.txt, then feed them into Nuclei: nuclei -l endpoints.txt -t vulnerabilities/ -severity medium,high,critical. This validates FFUF-discovered endpoints for actual exploitable vulnerabilities rather than just confirming their existence.Run directory fuzzing, vhost discovery, and vulnerability validation autonomously across your entire target scope — no manual pipeline wiring required.