FFUF (Fuzz Faster U Fool) is a fast web fuzzer written in Go that has become the go-to tool for many penetration testers, replacing older alternatives with its speed, flexibility, and powerful filtering options. Whether you’re hunting hidden directories, fuzzing parameters, or discovering subdomains, FFUF handles it all with a clean syntax built around a single keyword: FUZZ.
Installing FFUF
On Kali Linux:
sudo apt install ffuf
Via Go (for the latest version):
go install github.com/ffuf/ffuf/v2@latest
Or download a pre-built binary from the releases page on GitHub and place it in /usr/local/bin/:
chmod +x ffuf && sudo mv ffuf /usr/local/bin/
Confirm it’s working:
ffuf -V
The FUZZ Keyword
FFUF’s core mechanic is simple: place the word FUZZ anywhere in a URL, header, cookie, or POST body, and FFUF substitutes each wordlist entry in that position. This makes it incredibly versatile.
Basic Directory Fuzzing
ffuf -u https://target.com/FUZZ -w /usr/share/seclists/Discovery/Web-Content/common.txt
FFUF will display every response by default, which is usually too noisy. The filtering flags are where the real power lives.
Filtering Responses
FFUF’s filtering system is the key differentiator from older tools. You can filter by status code, response size, word count, or line count.
| Flag | Filters by | Example |
|---|
-fc | Status code (filter OUT) | -fc 404 |
-mc | Status code (match only) | -mc 200,301 |
-fs | Response size (filter OUT) | -fs 1234 |
-ms | Response size (match only) | -ms 500-2000 |
-fw | Word count (filter OUT) | -fw 10 |
-mw | Word count (match only) | -mw 50 |
-fl | Line count (filter OUT) | -fl 9 |
-ml | Line count (match only) | -ml 20 |
The Calibration Workflow
Before running a real scan, test with a non-existent path to see what a 404 response looks like:
curl -s https://target.com/thispageclearlydoesnotexist123 | wc -c
If the 404 response is always 1,234 bytes, filter it out:
ffuf -u https://target.com/FUZZ \
-w /usr/share/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt \
-fc 404 \
-fs 1234
Alternatively, use -ac (auto-calibrate) to let FFUF figure out baseline responses automatically:
ffuf -u https://target.com/FUZZ -w common.txt -ac
File Extension Fuzzing
Append extensions to discover actual files:
ffuf -u https://target.com/FUZZ \
-w /usr/share/seclists/Discovery/Web-Content/common.txt \
-e .php,.html,.txt,.bak,.zip,.old \
-fc 404
POST Data Fuzzing
FFUF handles POST body fuzzing with the -d flag and the -X POST method. This is useful for testing login endpoints, search fields, or API parameters.
First capture a real login request. Then fuzz the password field:
ffuf -u https://target.com/login \
-X POST \
-d "username=admin&password=FUZZ" \
-H "Content-Type: application/x-www-form-urlencoded" \
-w /usr/share/wordlists/rockyou.txt \
-fc 302 \
-fs 1500
Here we filter out 302 redirects (which are the “wrong password, try again” responses) and filter out the fixed-size failed login page.
Fuzzing JSON API Endpoints
ffuf -u https://api.target.com/v1/users \
-X POST \
-d '{"username":"FUZZ","password":"password"}' \
-H "Content-Type: application/json" \
-w /usr/share/seclists/Usernames/top-usernames-shortlist.txt \
-mc 200
Subdomain Enumeration
FFUF can brute-force subdomains by fuzzing the Host header — the same principle as Gobuster’s vhost mode:
ffuf -u https://target.com \
-H "Host: FUZZ.target.com" \
-w /usr/share/seclists/Discovery/DNS/subdomains-top1million-5000.txt \
-fc 404 \
-fs 1234
The trick is identifying and filtering the baseline response for non-existent subdomains. Run a quick test first:
curl -H "Host: thisdoesnotexist.target.com" https://target.com -o /dev/null -w "%{size_download}\n"
Then filter that size with -fs.
Parameter Fuzzing
Discover hidden GET parameters:
ffuf -u "https://target.com/page?FUZZ=value" \
-w /usr/share/seclists/Discovery/Web-Content/burp-parameter-names.txt \
-mc 200 \
-fs 1234
And hidden values for a known parameter:
ffuf -u "https://target.com/page?id=FUZZ" \
-w /usr/share/seclists/Fuzzing/Integers/Integers_1-1000.txt \
-mc 200
Rate Limiting
FFUF defaults to unlimited speed, which can be too aggressive. Control the rate:
-rate — Requests per second:
ffuf -u https://target.com/FUZZ -w common.txt -rate 50
-t — Concurrent threads (default: 40):
ffuf -u https://target.com/FUZZ -w common.txt -t 20
-p — Pause between requests (seconds, supports decimals):
ffuf -u https://target.com/FUZZ -w common.txt -p 0.1
For particularly sensitive targets or WAF-protected systems, use -rate 10 -p 0.5 to stay under most detection thresholds.
Saving Output
FFUF supports multiple output formats:
# JSON (best for automation)
ffuf -u https://target.com/FUZZ -w common.txt -o results.json -of json
# CSV
ffuf -u https://target.com/FUZZ -w common.txt -o results.csv -of csv
# Markdown table
ffuf -u https://target.com/FUZZ -w common.txt -o results.md -of md
Multiple Wordlists (Multi-Position Fuzzing)
FFUF supports custom keyword names for fuzzing multiple positions simultaneously:
ffuf -u https://target.com/FUZZDIR/FUZZFILE \
-w /usr/share/seclists/Discovery/Web-Content/common.txt:FUZZDIR \
-w /usr/share/seclists/Discovery/Web-Content/common.txt:FUZZFILE \
-fc 404
Practical Workflow
- Start with auto-calibration:
ffuf -u https://target.com/FUZZ -w common.txt -ac
- Note the baseline response size and apply
-fs for precise filtering
- Escalate wordlists: common → medium → large based on time available
- Check interesting finds manually: Open 301/403 responses in Burp and dig deeper
- Fuzz extensions on discovered directories:
/admin/FUZZ with -e .php,.bak
FFUF’s speed and filtering precision make it ideal for time-boxed engagements. Once you internalize the filter flags, you’ll find it’s faster to get clean, actionable results than with almost any other fuzzer available.