API fuzzing discovers routes, versions, methods, resources, actions, and schemas. We use it after basic directory fuzzing because /api, /graphql, /swagger, /openapi.json, and versioned prefixes often expose the real application logic behind a thin frontend.
Common API entry points:
/api
/api/v1
/api/v2
/graphql
/graphiql
/swagger
/swagger.json
/swagger-ui
/openapi.json
/docs
/redoc
/actuator
Find API roots:
ffuf -u http://127.0.0.1:5000/FUZZ \
-w /usr/share/seclists/Discovery/Web-Content/api/api-endpoints.txt \
-mc 200,204,301,302,307,401,403
If that list is unavailable, start with a small custom list:
printf "api\napi/v1\napi/v2\ngraphql\nswagger\nswagger.json\nopenapi.json\ndocs\nredoc\nactuator\n" > api-roots.txt
ffuf -u http://127.0.0.1:5000/FUZZ \
-w api-roots.txt \
-mc 200,204,301,302,307,401,403
Fuzz resources under an API prefix:
ffuf -u http://127.0.0.1:5000/api/FUZZ \
-w /usr/share/seclists/Discovery/Web-Content/api/objects.txt \
-mc 200,204,301,302,307,401,403 \
-fs 1234
Fuzz version prefixes:
printf "v1\nv2\nv3\nbeta\ninternal\nprivate\nadmin\n" > api-versions.txt
ffuf -u http://127.0.0.1:5000/api/FUZZ/users \
-w api-versions.txt \
-mc 200,204,301,302,307,401,403
Fuzz nested API actions:
ffuf -u http://127.0.0.1:5000/api/users/FUZZ \
-w /usr/share/seclists/Discovery/Web-Content/raft-small-words.txt \
-mc 200,204,301,302,307,401,403
Test HTTP methods:
for m in GET POST PUT PATCH DELETE OPTIONS; do
echo "== $m =="
curl -i -X "$m" http://127.0.0.1:5000/api/users
done
Use ffuf with JSON bodies:
ffuf -u http://127.0.0.1:5000/api/users \
-X POST \
-H "Content-Type: application/json" \
-d '{"name":"FUZZ"}' \
-w /usr/share/seclists/Fuzzing/special-chars.txt \
-mc all \
-fs 1234
Use wfuzz for regex-based API success:
wfuzz -w api-objects.txt \
--ss '"id"|"name"|"role"|"status"' \
http://127.0.0.1:5000/api/FUZZ
Spider first, fuzz second:
katana -u http://127.0.0.1:5000/ -silent -jc -kf all -o urls.txt
grep -Ei '/api/|graphql|swagger|openapi' urls.txt | sort -u
API findings to test next:
IDOR on numeric IDs
mass assignment on JSON fields
SQLi in filters and sort keys
XSS in JSON rendered by frontend
SSTI where API data becomes templates
command injection in admin/operator actions
auth bypass on method changes
excessive data exposure
Notes
An API 401 or 403 can still be a valid finding. It confirms the route exists and gives us something to retest after authentication or role changes.
Always compare GET, POST, PUT, PATCH, DELETE, and OPTIONS where the application exposes API resources.