Skip to content
EIEnes Ismaili
2 min read

Finding Swagger files before an attacker does

A Nuclei template that locates Swagger and OpenAPI definitions, because an unlisted API is still an exposed API.

ToolingAPI

An API definition is a map of the application. Endpoints, parameters, authentication schemes, sometimes example values. When it is left exposed, an attacker does not have to guess the surface area. They can read it.

I wrote a Nuclei template to find these files systematically.

Why it matters

Swagger and OpenAPI definitions are usually generated for developers. They get deployed with the application and then forgotten. Nobody links to them, so nobody notices them, and they rarely appear in a sitemap or a crawl.

But an unlisted URL is not a private URL. A short list of conventional paths finds them in seconds, and what comes back is often more detailed than any reconnaissance output.

A definition file can reveal:

  • endpoints that are not documented anywhere else
  • parameters and object identifiers worth testing
  • authentication schemes and token locations
  • internal hostnames and staging URLs in example values
  • deprecated endpoints that were never removed

The template

It checks the conventional locations for Swagger UI and raw definition files, and matches on the response body rather than just the status code, so it does not fire on soft 404 pages.

Template and instructions: github.com/enes-ismaili/swagger

How I use it

Discovery, not exploitation. Run it early, then feed what it finds into the real testing:

  1. Import the definition into Burp or Postman and walk every endpoint with the roles you have.
  2. Diff the definition against the routes you were told about. Anything extra is interesting.
  3. Check whether the definition leaks internal hosts or credentials in examples.

The fix

Do not publish definitions to production unless the API is public by design. If it has to be reachable, put it behind authentication and strip internal hostnames from examples.

An unlisted URL is not a private URL.