Wfuzz: Web fuzzing of directories, parameters, headers, and VHosts

Wfuzz for web fuzzing: directory and parameter commands, VHost discovery, headers, cookies, filters, SecLists, encoders, and WAF bypass techniques.
- Posted on 2026-08-16
- Reading time: 9 min
Wfuzz: Guide to Web Fuzzing, Parameter Fuzzing, Directory and Brute Force #
wfuzz is a Python web fuzzer that replaces the keyword FUZZ with every wordlist entry anywhere in an HTTP request — URLs, GET/POST parameters, headers, cookies, JSON bodies. While gobuster and feroxbuster are optimized for brute force directory entry, wfuzz is completely genericYou can fuze any field, with multiple simultaneous wordlists and built-in encoders. This makes it the perfect tool when you need to test for injection points, hidden parameters, vhosts, or any non-standard scenario.
Prerequisites: wordlist (install with SecLists ) and Burp Suite as a proxy to inspect requests.
What is Wfuzz? #
Wfuzz is an open source web fuzzer written in Python that allows you to replace a position FUZZ within an HTTP request with the values of a wordlist. It can be used on directories and files, GET/POST parameters, headers, cookies, virtual hosts, and generally on any HTTP input point reachable in a request.
How does Wfuzz work? #
Wordlist
↓
Ogni entry sostituisce FUZZ nella request
↓
Request inviata al target
↓
Response ricevuta
↓
Filtri (--hc, --sc, --hl, --hw, --hh, --hs, --ss)
↓
Risultati interessantiIn practice: write a request with FUZZ Instead of the value you want to test, you attach a wordlist, and wfuzz sends a request for each row in the wordlist. Filters are used to filter out the noise (thousands of identical/irrelevant answers) and highlight only what matters.
Wfuzz vs ffuf vs feroxbuster vs gobuster #
Before you begin: These tools do similar things, but with different strengths. Choose based on the task at hand.
| tool | Language | Swift | Multi-fuzzing | encoders | Recursion | When to use it |
|---|---|---|---|---|---|---|
| wfuzz | Python | ★★★ | ✅ FUZZ+FUZ2Z+FUZ3Z | ✅ many | Manual -R | Maximum flexibility, parameter fuzzing, encoders |
| fuf | Go | ★ ★ ★ ★ ★ | ✅ -w w1:K1 -w w2:K2 | Base | Cars --recursion | Fast directory fuzzing, everyday use |
| feroxbuster | Peace | ★ ★ ★ ★ ★ | ❌ | ❌ | Car, aggressive | Deep recursion, maximum speed |
| gobuster | Go | ★ ★ ★ ★ | ❌ | ❌ | ❌ | Simplicity, subdomain DNS, S3 bucket |
| dirbuster | Java | ★★ | ❌ | ❌ | ✅ GUI | Legacy, GUI for those who prefer visual |
Is wfuzz better than ffuf? Not at all: ffuf is generally preferable for fast directory fuzzing, while wfuzz is more interesting when you need multi-position, parameter fuzzing, header/cookie fuzzing, and encoders—the others just can't do that.
Wfuzz vs Burp Intruder? Burp Intruder is more convenient for manual, iterative fuzzing within the Burp workflow (with token/CSRF management via macros). Wfuzz is better suited when you want to automate from the command line, integrate it into scripts, or launch mass scans without going through the UI.
| If you have to… | Usa |
|---|---|
| Quick Directory | fuf |
| Parameter fuzzing | wfuzz |
| Multi-position | wfuzz |
| Encoder | wfuzz |
| Aggressive recursion | feroxbuster |
| Simple DNS/VHost | gobuster |
Installation #
Kali already includes it. If it's missing:
sudo apt install wfuzz -y
# oppure
pip3 install wfuzzThe default wordlists are in /usr/share/wfuzz/wordlist/. For serious fuzzing use SecLists in /usr/share/seclists/.
Basic syntax and mandatory filters #
wfuzz [opzioni] -w WORDLIST URL_CON_FUZZThe options you will always use:
| Flag | What does he do |
|---|---|
-w wordlist | Specify wordlist (repeat for multi-position) |
-c | Colored output |
-t N | Thread (default 10) |
--hc N | Hide responses with status code N — always use it |
--sc N | Show only responses with status code N |
--hl N | Hide answers with N lines |
--hw N | Hide answers with N words |
--hh N | Hide responses with exactly N characters |
--hs "stringa" | Hide responses that contain that string |
--ss "stringa" | Show only responses that contain that string |
-d "data" | Body POST |
-H "Header: val" | Custom HTTP headers |
-b "cookie=val" | Cookie |
-p proxy | Proxy (Burp Suite: 127.0.0.1:8080) |
-f file,formato | Save output (json, csv, html) |
Without
--hc 404, wfuzz prints every response, and the output is unusable. This is the first filter you should always add. The exact behavior of some flags (delay, recursion) may vary between versions of wfuzz. Always checkwfuzz -hon your build before blindly relying on these commands in a real-world engagement.
Wfuzz for directory and file fuzzing #
# Base — il punto di partenza su qualsiasi target
wfuzz -c -w /usr/share/seclists/Discovery/Web-Content/common.txt \
--hc 404 http://target.com/FUZZID Response Lines Word Chars Payload
================================================================
00042: C=200 12 L 45 W 512 Ch "admin"
00137: C=301 9 L 28 W 319 Ch "backup"
00891: C=403 7 L 22 W 285 Ch "config"C=301 It's a redirect — follow it with your browser. C=403 It exists but is forbidden — still interesting, often bypassable.
# Fuzza con estensione specifica
wfuzz -c -w /usr/share/seclists/Discovery/Web-Content/common.txt \
--hc 404 http://target.com/FUZZ.php
# Fuzza path + estensione contemporaneamente (FUZZ + FUZ2Z)
wfuzz -c \
-w /usr/share/seclists/Discovery/Web-Content/common.txt \
-w /usr/share/seclists/Fuzzing/Extensions/Web-Extensions.fuzz.txt \
--hc 404 "http://target.com/FUZZ.FUZ2Z"
# Ricorsivo (depth 2) — dopo aver trovato /admin, entra dentro
wfuzz -c -w /usr/share/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt \
--hc 404 -R 2 http://target.com/FUZZ/Recommended wordlists for directories:
| Wordlist | Entry | When |
|---|---|---|
common.txt | 4.723 | Initial quick win |
directory-list-2.3-medium.txt | 220.000 | Standard Assessment |
directory-list-2.3-big.txt | 1.27M | In-depth assessment |
api/api-endpoints.txt | 13.000 | REST API |
Typical mistake: throwing it right away
directory-list-2.3-big.txton target in production. Start withcommon.txt, then scale. With 1.27 million highly threaded requests, you can trigger rate limits or accidental DoS.
Wfuzz for GET and POST parameter fuzzing #
Wfuzz excels where ffuf and feroxbuster don't easily reach: uncovering hidden parameters and testing injection points on any field.
GET parameter discovery #
# Fuzza il nome del parametro — cosa accetta questa pagina?
wfuzz -c -w /usr/share/seclists/Discovery/Web-Content/burp-parameter-names.txt \
--hh 0 "http://target.com/search.php?FUZZ=test"00234: C=200 45 L 120 W 1823 Ch "query"
00891: C=200 12 L 34 W 412 Ch "debug"--hh 0 Hides empty responses (parameter ignored by the server). Everything else has a different response → valid parameter.
IDOR and injection testing #
# IDOR — testa accesso a risorse di altri utenti
wfuzz -c -z range,1-1000 --hc 404,403 \
"http://target.com/api/user/FUZZ/profile"
# Testa injection SQL su parametro id (vedi la guida a SQL injection)
wfuzz -c -w /usr/share/seclists/Fuzzing/SQLi/Generic-SQLi.txt \
--hs "not found" \
"http://target.com/item.php?id=FUZZ"POST parameter fuzzing #
# Login form — fuzza la password con username fisso
wfuzz -c -w /usr/share/seclists/Passwords/Common-Credentials/10k-most-common.txt \
--hc 302 \
-d "username=admin&password=FUZZ" \
http://target.com/login.php--hc 302 Hides failure redirects. When a 200 response appears, password found.
# Se il server risponde sempre 200 — filtra per testo di errore
wfuzz -c -w /usr/share/seclists/Passwords/Common-Credentials/10k-most-common.txt \
--hs "Invalid credentials" \
-d "username=admin&password=FUZZ" \
http://target.com/login.phpJSON parameter fuzzing #
# API JSON POST
wfuzz -c -w /usr/share/seclists/Discovery/Web-Content/api/api-endpoints.txt \
-H "Content-Type: application/json" \
-H "Authorization: Bearer TOKEN" \
-d '{"action":"FUZZ"}' \
--hc 404,400 http://target.com/api/v1Typical JSON API error: forgetting
-H "Content-Type: application/json"Without it, almost all APIs return 400, making it impossible to distinguish valid results.
Wfuzz for virtual host and subdomain discovery #
A single IP can host dozens of vhosts — admin panel, staging, internal APIs — that are not reachable from the main URL.
# Misura prima la dimensione della risposta di default
curl -s http://TARGET_IP/ | wc -c
# Output: 1423
# Virtual host discovery — nascondi baseline, mostra tutto il resto
wfuzz -c -w /usr/share/seclists/Discovery/DNS/subdomains-top1million-5000.txt \
-H "Host: FUZZ.target.com" \
--hh 1423 http://TARGET_IP/00089: C=200 312 L 1024 W 18432 Ch "admin"
00234: C=200 45 L 120 W 4821 Ch "staging"# Subdomain fuzzing (DNS)
wfuzz -c -Z \
-w /usr/share/seclists/Discovery/DNS/subdomains-top1million-5000.txt \
http://FUZZ.target.com/-Z ignore connection error (subdomain that does not exist → timeout, fuzzer does not crash).
Wfuzz for header and cookie fuzzing #
# Fuzza X-Forwarded-For — bypass IP whitelist su admin panel
wfuzz -c -w /usr/share/seclists/Fuzzing/IP-addresses.txt \
-H "X-Forwarded-For: FUZZ" \
--sc 200 http://target.com/admin/
# Fuzza User-Agent — aggira blocchi anti-bot
wfuzz -c -w /usr/share/seclists/Fuzzing/User-Agents/UserAgents.fuzz.txt \
-H "User-Agent: FUZZ" \
--hc 403 http://target.com/
# Fuzza session cookie — IDOR su sessioni numeriche
wfuzz -c -z range,1-50000 \
-b "sessionid=FUZZ" \
--hc 302,401 http://target.com/dashboard/HTTP Basic Auth #
# Brute force Basic Auth
wfuzz -c -w /usr/share/seclists/Passwords/Common-Credentials/top-passwords-shortlist.txt \
--basic "admin:FUZZ" --hc 401 \
http://target.com/protected/
# Fuzza anche username
wfuzz -c \
-w /usr/share/seclists/Usernames/top-usernames-shortlist.txt \
-w /usr/share/seclists/Passwords/Common-Credentials/10k-most-common.txt \
--basic "FUZZ:FUZ2Z" --hc 401 \
http://target.com/protected/What are FUZZ, FUZ2Z and FUZ3Z in Wfuzz? #
FUZZ identifies the first fuzzing position, FUZ2Z the second e FUZ3Z the third. Each position is associated with the corresponding wordlist based on the order in which you pass the parameters. -w: the first -w feed FUZZ, the second FUZ2Z, and so on.
# Path + estensione
wfuzz -c \
-w /usr/share/seclists/Discovery/Web-Content/common.txt \
-w /usr/share/seclists/Fuzzing/Extensions/Web-Extensions.fuzz.txt \
--hc 404 "http://target.com/FUZZ.FUZ2Z"
# Username + password su login
wfuzz -c \
-w /usr/share/seclists/Usernames/top-usernames-shortlist.txt \
-w /usr/share/seclists/Passwords/Common-Credentials/10k-most-common.txt \
-d "user=FUZZ&pass=FUZ2Z" --hc 302 \
http://target.com/loginThe number of requests =
len(w1) × len(w2)Two wordlists of 5.000 entries → 25 million requests. Calculate this first, especially on rate-limited targets.
Wfuzz Encoders: Encoding and Testing WAF Filters #
Encoders transform the payload before sending it. They don't guarantee bypass—they're used to test how the application (or any WAF running behind it) normalizes and interprets the encoded input, which is useful for both offensive and defensive normalization analysis.
# Elenco encoder disponibili
wfuzz -e encoders base64 – Encodes the given string as base64
md5 – Returns the md5 hash of the string
urlencode – URL-encodes special characters
html_escape – HTML entity encoding
hexlify – Converts string to hex
sha1 – Returns sha1 hash# URL encoding (caratteri speciali nei payload SQLi)
wfuzz -c -z file,/usr/share/seclists/Fuzzing/SQLi/Generic-SQLi.txt,urlencode \
--hs "error" "http://target.com/?id=FUZZ"
# Double URL encoding (test di normalizzazione a doppio layer)
wfuzz -c -z file,sqli.txt,urlencode-urlencode \
"http://target.com/?id=FUZZ"
# Base64 (API che accettano parametri encodati)
wfuzz -c -z file,payloads.txt,base64 \
-d "token=FUZZ" http://target.com/api/
# MD5 di ogni password (form che hashano lato server)
wfuzz -c -z file,passwords.txt,md5 \
-d "hash=FUZZ" http://target.com/loginHow to filter Wfuzz results #
Filtering is essential because wfuzz can generate thousands of seemingly valid answers. Filters --hc, --sc, --hl, --hw, --hh, --hs e --ss They serve to isolate interesting responses from noise.
| Filter | Flag | When to use it |
|---|---|---|
| By status code | --hc 404,403 / --sc 200,301 | Always — first filter |
| By lines | --hl N | All 404s have the same number of lines |
| For words | --hw N | All 404s have the same number of words |
| By character | --hh N | Hide answers of exact size N |
| Regex show | --ss "pattern" | You only want responses containing a string |
| Regex hide | --hs "error page" | Hide replies with specific text |
| Expression | --filter "c==200 and l>10" | Advanced combined filter |
# Filtro combinato: status 200 E più di 10 linee
wfuzz -c -w wordlist.txt \
--filter "c==200 and l>10" http://target.com/FUZZ
# Salva output JSON per analisi successiva
wfuzz -c -w wordlist.txt --hc 404 \
-f /tmp/results.json,json http://target.com/FUZZWfuzz with Burp Suite and rate limiting #
# Passa tutto per Burp Suite (ispeziona ogni request)
wfuzz -c -w wordlist.txt --hc 404 \
-p 127.0.0.1:8080 http://target.com/FUZZ
# Target lento o con rate limiting
wfuzz -c -w wordlist.txt --hc 404 \
-t 5 -s 0.5 http://target.com/FUZZ
# -t 5: 5 thread (default 10)
# -s 0.5: delay tra request (verifica l'unità sulla tua versione)
# User-Agent legittimo + cookie sessione (fuzzing da autenticato)
wfuzz -c -w wordlist.txt --hc 302,403 \
-H "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64)" \
-H "Cookie: sessionid=abc123; PHPSESSID=xyz789" \
http://target.com/FUZZWhen to use Wfuzz #
Wfuzz is especially useful when the fuzzing point isn't limited to the URL path. For standard directory discovery, tools like ffuf are often faster; wfuzz becomes the right choice when you need to check parameters, headers, cookies, body, or multiple locations at once—that's where its generality pays off.
How to Use Wfuzz During a Web Pentest #
1. DIRECTORY QUICK WIN
└─ common.txt + --hc 404
└─ File fuzzing con .php, .bak, .zip, .txt
2. APPROFONDIMENTO SU PATH TROVATI
└─ medium.txt su /admin/, /api/, /backup/
└─ Ricorsione -R 2
3. VHOST / SUBDOMAIN
└─ Misura baseline → fuzza Host header con --hh N
└─ DNS subdomain con -Z
4. PARAMETER DISCOVERY
└─ burp-parameter-names.txt su endpoint trovati
└─ IDOR range numerico su /api/user/FUZZ/
5. INJECTION TESTING
└─ SQLi wordlist su parametri trovati (collega con guida SQL injection)
└─ XSS payloads su input fields
6. AUTH BRUTEFORCE
└─ Identifica risposta di errore → configura --hs o --hc
└─ Lancia con 10k-most-common.txt
7. OUTPUT
└─ -f risultati.json,json → analisi in Burp/DradisTroubleshooting #
| Problem | Cause | Solution |
|---|---|---|
| Output flood of results | Manca --hc 404 | Always add --hc 404 as a baseline |
| All answers same size | Server responds the same for each path | Usa --hl o --hw in place of --hc |
| IP banned quickly | Too many threads / rate limit | -t 5 -s 0.5 |
| HTTPS — Invalid certificate | Self-signed SSL | Add --no-check-certificate |
| VHost finds nothing | Unfiltered baseline | Measure with curl -s http://IP/ | wc -c then --hh N |
| Wrong encoding | Special characters in the wordlist | encoder: -z file,list.txt,urlencode |
| Very slow multi-position | Huge Cartesian product | Reduce wordlist or accept duration |
| Wfuzz crashes with no output | Target is not responding | Reduce thread, add --req-delay 5 |
FAQ #
What is Wfuzz?
An open source web fuzzer in Python that replaces a position FUZZ in an HTTP request with the values of a wordlist.
What is Wfuzz used for? To discover directories, files, hidden parameters, vhosts, and to test headers, cookies, login forms, and injection points—basically any field in an HTTP request.
Wfuzz or ffuf for directory fuzzing? Ffuf is significantly faster (Go vs. Python) and has cleaner output. For standard directories, use ffuf. Wfuzz comes in handy when you need encoders, advanced multi-positioning, or header/cookie fuzzing.
How to use FUZZ in Wfuzz?
Enter the keyword FUZZ at the point of the request you want to test (URL, header, body, cookie) and connect a wordlist with -w. Wfuzz replaces FUZZ with each line of the wordlist, one request at a time.
What are FUZ2Z and FUZ3Z?
They are the second and third fuzzing positions in a multi-position command, each fed by their respective wordlist passed with -w, in the order you specify it.
How do I filter Wfuzz responses?
With --hc/--sc for status code, --hl/--hw/--hh for lines/words/characters, --hs/--ss for textual content, or --filter for combined expressions.
Does Wfuzz support POST fuzzing?
Yes with -d "campo=FUZZ" for form-encoded or JSON body.
Can Wfuzz fuze headers and cookies?
Yes with -H "Header: FUZZ" for headers and -b "cookie=FUZZ" for cookies.
How do I fuzz on an authenticated application?
Capture the post-login session cookie with Burp Suite, then use it with -H "Cookie: session=abc123" in every request.
How do I handle CSRF tokens? Wfuzz doesn't handle dynamic CSRF. For that, use Burp Intruder with macros, or a Python script with requests that extracts the token before each request.
What is the best wordlist?
common.txt for quick win, directory-list-2.3-medium.txt for complete assessment, burp-parameter-names.txt for parameter discovery. All in SecLists.
How do I save the results for the report?
-f output.json,json for automated parsing, -f output.html,html for immediate readability. JSON is convenient for importing into reporting tools like Dradis.
Wfuzz Cheat Sheet #
=== DIRECTORY ===
Base: wfuzz -c -w common.txt --hc 404 http://target/FUZZ
+Estensione: wfuzz -c -w common.txt --hc 404 http://target/FUZZ.php
Multi-ext: wfuzz -c -w names.txt -w ext.txt --hc 404 "http://target/FUZZ.FUZ2Z"
Ricorsivo: wfuzz -c -w medium.txt --hc 404 -R 2 http://target/FUZZ/
=== PARAMETER ===
GET nome: wfuzz -c -w burp-params.txt --hh 0 "http://target/page?FUZZ=test"
GET valore: wfuzz -c -z range,1-1000 --hc 404 "http://target/item?id=FUZZ"
POST: wfuzz -c -w passwords.txt -d "user=admin&pass=FUZZ" --hc 302 http://target/login
JSON POST: wfuzz -c -w endpoints.txt -H "Content-Type: application/json" -d '{"a":"FUZZ"}' --hc 400 http://target/api
=== VHOST / SUBDOMAIN ===
VHost: wfuzz -c -w subdomains.txt -H "Host: FUZZ.target.com" --hh BASELINE http://IP/
Subdomain: wfuzz -c -Z -w subdomains.txt http://FUZZ.target.com/
=== HEADER / COOKIE ===
Header: wfuzz -c -w ips.txt -H "X-Forwarded-For: FUZZ" --sc 200 http://target/admin/
Cookie: wfuzz -c -z range,1-50000 -b "session=FUZZ" --hc 302 http://target/dashboard/
=== AUTH ===
Basic: wfuzz -c -w passwords.txt --basic admin:FUZZ --hc 401 http://target/protected/
Login: wfuzz -c -w passwords.txt -d "u=admin&p=FUZZ" --hs "Invalid" http://target/login
=== MULTI-POSITION ===
Doppio: wfuzz -c -w list1.txt -w list2.txt "http://target/FUZZ/FUZ2Z"
Login 2D: wfuzz -c -w users.txt -w passwords.txt -d "u=FUZZ&p=FUZ2Z" --hc 302 http://target/login
=== ENCODERS ===
URL: -z file,list.txt,urlencode
Double URL: -z file,list.txt,urlencode-urlencode
Base64: -z file,list.txt,base64
MD5: -z file,list.txt,md5
=== FILTRI ===
--hc 404,403 Hide status code
--sc 200,301 Show solo status code
--hl N Hide risposte con N linee
--hh N Hide risposte con N caratteri
--hs "stringa" Hide contenente stringa
--ss "stringa" Show contenente stringa
--filter "c==200 and l>5" Espressione combinata
=== PROXY / EVASION ===
Burp: -p 127.0.0.1:8080
Delay: -s 0.5
Thread: -t 5 (default 10)
UA custom: -H "User-Agent: Mozilla/5.0..."
Con cookie: -H "Cookie: session=abc123"
=== OUTPUT ===
JSON: -f output.json,json
HTML: -f output.html,htmlRelated guides on hackita.it:
- ffuf: Fast Web Fuzzing in Go
- feroxbuster: Recursive Directory Fuzzing
- gobuster: Directory, DNS and VHost Discovery
- Burp Suite: Intercept and Modify HTTP Requests
- SQL Injection: A Complete Guide
- Wordlist and SecLists: Operational Guide
- Web Application Attacks








