feroxbuster
feroxbuster is a fast, recursive content discovery scanner: give it a URL and a wordlist and it walks the site for directories and files, automatically diving into every directory it finds. Reach for it the moment Nmap hands you a web port and you need to know what paths exist before testing them by hand, whether that is a CTF box, a homelab admin panel, or an authorized web assessment.
Mental model: feroxbuster -u URL -w WORDLIST. Recursion is on by default; every other flag either bounds it, filters the noise, or shapes the request.
New to content discovery? Core concepts
- Target URL (
-u): the base the scan starts from, scheme included, for examplehttp://TARGET_IP:8080/ - Wordlist (
-w): the candidate paths tried against the base; quality beats raw size - Recursion: the default behavior, a found directory becomes a new base;
-dcaps depth,-nturns it off - Status codes:
200found,301/302redirect,403forbidden-but-exists,404absent - Extensions (
-x): append file types soadminalso triesadmin.php,admin.bak - Filters: drop noise by status
-C, size-S, words-W, lines-N, or regex--filter-regex - Soft-404: a page that returns
200for everything; you filter it by its constant size or word count - Threads (
-t) and rate limit (--rate-limit): trade speed for load on the target
When to reach for feroxbuster (and when not)
Reach for it to map an unknown web app, brute directories after Nmap finds an HTTP port, dive recursively into nested paths, or hunt file-backed content (.php, .bak, config backups) across a whole tree in one pass.
Reach for something else when the app is flat and one level deep (gobuster is simpler), when you need to fuzz parameters, headers, or POST bodies rather than paths (ffuf), when you already know the exact path (just curl it), or when the target is fragile and a fast recursive crawl would knock it over.
Install, update, verify#
sudo apt install -y feroxbuster # Debian / Ubuntu / Kali
sudo dnf install -y feroxbuster # Fedora / RHEL
brew install feroxbuster # macOS
cargo install feroxbuster # build the latest from source
sudo apt install --only-upgrade -y feroxbuster # update (apt)
cargo install feroxbuster --force # update (cargo)
feroxbuster --version # version string
command -v feroxbuster # confirm it is on PATH
Wordlists ship separately. Install SecLists with sudo apt install -y seclists (it lands in /usr/share/seclists); throughout, WORDLIST means a file like /usr/share/seclists/Discovery/Web-Content/common.txt. Smoke-test against a throwaway local server so you touch nothing external:
python3 -m http.server 8000 &
feroxbuster -u http://127.0.0.1:8000/ -w /usr/share/seclists/Discovery/Web-Content/common.txt
Flags you’ll actually use#
Skim these first; the cheat sheet below is these flags combined.
| Flag | Does | Flag | Does |
|---|---|---|---|
-u | Target URL, the base to scan | -C | Filter out these status codes |
-w | Wordlist of candidate paths | -S | Filter out a response size |
-n | No recursion (flat, one level) | -W | Filter out a word count |
-d | Cap recursion depth | -N | Filter out a line count |
-x | Append extensions (php,txt,bak) | --filter-regex | Filter out bodies matching a regex |
-t | Threads (concurrency) | -H | Add a request header |
--rate-limit | Cap requests per second | -b | Send cookies |
-L | Cap concurrent directory scans | -r | Follow redirects |
-s | Report only these status codes | -k | Skip TLS verification (labs) |
-f | Append a trailing slash to words | --burp | Proxy to Burp + skip TLS in one flag |
--auto-tune | Back off on errors automatically | -o | Save results to a file |
--dont-scan | Exclude URLs from recursion | --json | JSON-lines output for tooling |
Cheat sheet#
Every block starts simple and adds one flag at a time, so you can stop at the line that does the job.
# Build up a scan: stop at the line you need
feroxbuster -u URL -w WORDLIST # 1. recursive discovery (default)
feroxbuster -u URL -w WORDLIST -d 2 # 2. + cap recursion at depth 2
feroxbuster -u URL -w WORDLIST -d 2 -x php,txt,html # 3. + try file extensions
feroxbuster -u URL -w WORDLIST -d 2 -x php,txt -o scans/web.txt # 4. + save the output
# Recursion control
feroxbuster -u URL -w WORDLIST -n # flat, one level, no recursion
feroxbuster -u URL -w WORDLIST -d 1 # recurse one level only
feroxbuster -u URL -w WORDLIST -L 4 # at most 4 directories scanned at once
feroxbuster -u URL -w WORDLIST --dont-scan 'logout' # never recurse into matching URLs
# Filter the soft-404 noise (measure it first, then drop it)
feroxbuster -u URL -w WORDLIST -C 404 # hide 404s
feroxbuster -u URL -w WORDLIST -S 1789 # drop a known junk byte size
feroxbuster -u URL -w WORDLIST -W 12 # drop a known word count
feroxbuster -u URL -w WORDLIST -N 40 # drop a known line count
feroxbuster -u URL -w WORDLIST --filter-regex 'Not Found' # drop bodies matching a regex
# Extensions and file hunting
feroxbuster -u URL -w WORDLIST -x php,html,txt,bak # append extensions to each word
feroxbuster -u URL -w WORDLIST --collect-extensions # learn extensions from responses, add them
feroxbuster -u URL -w WORDLIST --collect-backups # request .bak/.old copies of found files
feroxbuster -u URL -w WORDLIST -f # add a trailing slash to each word
# Auth, headers, methods
feroxbuster -u URL -w WORDLIST -b 'session=TOKEN' # send a session cookie
feroxbuster -u URL -w WORDLIST -H 'Authorization: Bearer TOKEN' # bearer token
feroxbuster -u URL -w WORDLIST -m POST # send POST instead of GET
feroxbuster -u URL -w WORDLIST -a 'Mozilla/5.0' # set a User-Agent
# Speed and politeness
feroxbuster -u URL -w WORDLIST -t 10 # fewer threads
feroxbuster -u URL -w WORDLIST --rate-limit 50 # cap requests per second
feroxbuster -u URL -w WORDLIST --auto-tune # slow down automatically on errors
feroxbuster -u URL -w WORDLIST --auto-bail # abort if the target starts erroring out
# TLS, proxy, redirects
feroxbuster -u URL -w WORDLIST -k # skip self-signed cert checks (labs)
feroxbuster -u URL -w WORDLIST -r # follow redirects instead of reporting them
feroxbuster -u URL -w WORDLIST -p http://127.0.0.1:8080 # route through a proxy
feroxbuster -u URL -w WORDLIST --burp # proxy to Burp + skip TLS in one flag
# Output and resume
feroxbuster -u URL -w WORDLIST -o scans/web.txt # plain text for notes
feroxbuster -u URL -w WORDLIST --json -o scans/web.json # JSON lines for tooling
feroxbuster --stdin -w WORDLIST < targets.txt # scan many URLs, one per line
feroxbuster --resume-from ferox-1712180000.state # continue an interrupted scan
jq -r 'select(.type=="response") | .url' scans/web.json | sort -u # pull found URLs from JSON
Command breakdowns#
Each block below explains one situation, the exact command, and what to expect back.
Run your first recursive scan#
feroxbuster -u http://TARGET_IP/ -w /usr/share/seclists/Discovery/Web-Content/common.txt
Streams status/size/path lines and dives into every directory it finds. This is the whole tool in one command; everything else just bounds or filters it. A summary of found paths prints at the end.
Cap how deep recursion goes#
feroxbuster -u URL -w WORDLIST -d 2
-d 2 scans the base and one level of found directories, no deeper. Start shallow and widen only if the results justify it; unbounded recursion is the fastest way to a runaway scan.
Do a flat, single-level scan#
feroxbuster -u URL -w WORDLIST -n
-n disables recursion entirely, so feroxbuster behaves like a plain directory scanner. A fast first look to learn an app’s shape, and its soft-404 behavior, before you let recursion loose.
Add file extensions to each word#
feroxbuster -u URL -w WORDLIST -x php,html,txt,bak
Each word is tried bare and with every extension, so admin also becomes admin.php, admin.bak, and so on. Keep the set small: four extensions roughly quintuple the request count.
Filter out a soft-404 by size#
feroxbuster -u URL -w WORDLIST -S 1789
When an app returns 200 with the same error page for everything, note that page’s byte size and drop it with -S. What is left is real. Run a flat pass first to learn the size to filter.
Filter noise by word count or regex#
feroxbuster -u URL -w WORDLIST -W 12 --filter-regex 'Not Found'
-W drops responses with a constant word count; --filter-regex drops bodies matching a pattern. Use these when the junk page’s byte size varies but its content stays the same.
Scan authenticated with a session cookie#
feroxbuster -u URL -w WORDLIST -b 'session=PLACEHOLDER_TOKEN'
-b attaches the cookie to every request so logged-in-only paths appear. For token APIs use -H 'Authorization: Bearer ...' instead. Grab the value from your browser dev tools or Burp.
Keep the scan gentle on a fragile target#
feroxbuster -u URL -w WORDLIST -t 10 --rate-limit 50
-t lowers concurrency and --rate-limit caps requests per second. Add --auto-tune to have feroxbuster back off on its own when the target starts returning errors.
Follow redirects to see where they land#
feroxbuster -u URL -w WORDLIST -r
By default a 301/302 is reported but not followed. -r follows it, which surfaces the real content behind directories that redirect to a trailing-slash or canonical URL.
Scan an HTTPS host with a self-signed cert#
feroxbuster -u https://TARGET_IP/ -w WORDLIST -k
-k skips certificate validation so a lab’s self-signed cert does not abort the scan. Labs only; do not make it a habit against real targets.
Route every request through Burp#
feroxbuster -u URL -w WORDLIST --burp
--burp is shorthand for -p http://127.0.0.1:8080 -k, sending every request into Burp’s history for inspection and replay. Use -p directly for any other proxy.
Save output for your notes and tooling#
feroxbuster -u URL -w WORDLIST -o scans/web.txt
feroxbuster -u URL -w WORDLIST --json -o scans/web.json
-o keeps a plain-text copy so you never re-run a loud scan to recover results. --json writes one object per line; parse it with jq. Save before you start manual testing.
Scan many targets from a file#
feroxbuster --stdin -w WORDLIST < targets.txt
Reads one in-scope URL per line and runs the same scan against each. Add --parallel 4 to scan several hosts at once. Confirm every line is in scope before you pipe it in.
Resume a scan you interrupted#
feroxbuster --resume-from ferox-1712180000.state
A clean Ctrl+C writes a .state file; --resume-from picks up where it stopped instead of re-walking the whole tree. Handy when a long recursive scan gets cut short.
Exclude a logout or trap path from recursion#
feroxbuster -u URL -w WORDLIST --dont-scan 'logout|signout'
--dont-scan keeps recursion out of paths that would log you out or loop forever. Give it the URL fragment or a regex of paths to leave alone.
Reading the output#
A result line reads: status code, method, then line, word, and char counts, then the URL. A redirect shows its target after =>.
200 GET 45l 120w 5324c http://TARGET_IP/admin/
301 GET 9l 28w 312c http://TARGET_IP/uploads => http://TARGET_IP/uploads/
| You see | Meaning | Do next |
|---|---|---|
200 | Exists, returned content | Your action items; open it |
301 / 302 | Redirect | Note the => target; add -r to follow |
401 | Needs auth | Rescan with a -b cookie or -H token |
403 | Exists but forbidden | Strong hint; note it, revisit later |
404 | Absent | Usually filtered; watch for soft-404s returning 200 |
| Same size across many hits | Soft-404 / catch-all | Filter that size with -S (or the word count with -W) |
The l / w / c counts are lines, words, and characters, and they are exactly what you match against with -N / -W / -S. Verify anything interesting in a browser or proxy before you trust it.
Troubleshooting#
| Problem | Cause | Fix |
|---|---|---|
command not found | Not installed / stale PATH | Reinstall; open a fresh shell |
Connection Refused | Nothing on that port | Confirm the service with curl or Nmap first |
Could not connect / hangs | Wrong scheme or host | Try https:// vs http://; check the URL and route |
Everything returns 200 | Soft-404 / catch-all route | Filter the junk size -S or word count -W |
| No results at all | Wordlist mismatch or WAF | Try another wordlist; slow down with --rate-limit |
| Scan never finishes | Recursion too deep / target slow | Cap -d, lower -t, or add -n |
| Certificate / TLS error | Self-signed lab cert | Add -k (labs only) |
| Blocked mid-scan | Too many requests per second | Add --rate-limit, lower -t, or --auto-tune |
Too many open files | Threads exceed the fd limit | Lower -t, or raise it with ulimit -n 8192 |
Gotchas#
- Recursion multiplies requests silently. A three-level tree with a 5000-word list is not 5000 requests, it is 5000 per discovered directory. Cap
-dand watch-Lbefore you point it at anything slow. -Cfilters status,-Sfilters size,-sallowlists status. The lowercase-sand the uppercase-S/-Cdo different jobs; mixing them up either hides real hits or shows all the noise.- Measure the soft-404 before you filter it. On some apps the junk size grows with the requested path length, so a size that filtered cleanly on
/aaacan leak on/aaaaaa. Prefer-Wor--filter-regexwhen the size drifts. - Extensions are appended, not substituted.
-x phptries bothadminandadmin.php; it never skips the bare word. Long extension lists blow up the request count fast. - State is saved on Ctrl+C, not on a crash. A clean interrupt writes a
.statefile you can--resume-from; a killed process or a full disk does not. Save with-oso results survive either way. --burpalso flips on-k. It assumes an intercepting proxy with its own cert, so it disables TLS verification too; do not reuse that profile against a target where cert validation actually matters.
Pairs with#
nmap finds the open HTTP/HTTPS ports that tell you where to point feroxbuster. Once it returns paths, curl reads headers and files cleanly, jq slices the --json output into URL lists, and WhatWeb or Nikto fingerprint the app behind them. Reach for gobuster when the site is flat and recursion is overkill, and for ffuf when the job shifts from finding paths to fuzzing parameters, headers, or POST bodies.