Kiterunner: content discovery built for APIs
Kiterunner · AGPL-3.0
Kiterunner is content discovery designed for APIs rather than websites. Generic brute-forcers send GET /path; real APIs use specific methods, headers, path parameters and content types. Kiterunner replays request templates derived from tens of thousands of real API specifications, so it finds routes that only respond to, say, POST with a JSON body.
Install
# binary release
wget https://github.com/assetnote/kiterunner/releases/latest/download/kiterunner_linux_amd64.tar.gz
tar xf kiterunner_linux_amd64.tar.gz && sudo mv kr /usr/local/bin/
# wordlists (Assetnote's routes-* kite files)
wget https://wordlists-cdn.assetnote.io/data/kiterunner/routes-large.kite Core commands
# scan with a kite wordlist
kr scan https://api.example.com -w routes-large.kite
# a list of hosts
kr scan hosts.txt -w routes-large.kite -o json -O results.json
# carry an auth header
kr scan https://api.example.com -w routes-large.kite
-H "Authorization: Bearer TOKEN"
# tune concurrency and rate
kr scan https://api.example.com -w routes-large.kite
--max-connection-per-host 5 -x 10 Output
{"method":"POST","path":"/api/v2/users/import","status":401,"content_length":52,
"host":"https://api.example.com"} A 401 here is a signal, not a failure: the route exists and requires auth.
Where it sits in Tandera
Kiterunner runs in the analyze phase of recon_api. Its results feed the flow’s shadow-endpoint synthesis — routes it discovers are compared against the API’s documented specification, and anything present but undocumented is surfaced as shadow surface.
Using it in a pentest
401 and 403 are the interesting results, not 200. They mean the endpoint exists and is protected. An undocumented endpoint that requires auth is precisely where broken object-level authorisation tends to live — test it with and without credentials.
Match the method, or you find nothing. The reason generic brute-forcers miss API routes is that they only send GET. Kiterunner’s method awareness is the point; do not fall back to a GET-only wordlist against an API.
Diff against the spec. If the client provided an OpenAPI document, the gap between what it documents and what Kiterunner finds is the shadow API — undocumented, and usually less tested.
Rate-limit against production. The route lists are large. Cap connections and coordinate the window with the client.