CLI tool
BishopFox/sj avatar
BishopFox/sj

sj: auditing a Swagger or OpenAPI definition for weak authentication

A tool for auditing endpoints defined in exposed (Swagger/OpenAPI) definition files.

879 stars114 forksGoMIT

At a glance

What is it?
sj is a Go command line tool from BishopFox that parses an exposed Swagger or OpenAPI definition, extracts the paths, parameters and accepted methods, and then either sends a series of requests to check for missing authentication or writes out the command templates for a human to run. It is a narrow tool with five subcommands, and the interesting one is how it separates scanning from replaying.
Who is it for?
sj suits a team that has published a Swagger or OpenAPI file and wants to know which of its endpoints answer requests that should have required authentication, and it suits an auditor who wants the request templates rather than a scanner that fires everything. It does not suit a job of finding endpoints nobody documented, since the tool starts from a definition file, and the brute subcommand is the one part of it that sends traffic without a specification to work from.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 4 days ago.
What is it written in?
Mainly Go, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

Five subcommands, and one of them does not use the definition

sj is a command line tool designed to assist with auditing of exposed Swagger or OpenAPI definition files by checking the associated API endpoints for weak authentication, and it also provides command templates for manual vulnerability testing. It works by parsing the definition file for paths, parameters and accepted methods, and then handing the results to one of five subcommands. automate crafts a series of requests and analyses the status code of the response. prepare generates a list of commands to use for manual testing. endpoints generates a list of raw API routes, with the note that path values will not be replaced with test data. brute sends a series of requests to a target to find operation definitions based on commonly used file paths, and convert converts a definition file from v2 to v3. The first four are variations on the same idea, but the fifth is different in kind, since it only rewrites the file rather than sending requests.

Building and installing it

To compile from source you need Go 1.22.5 or newer and then run go build inside the repository:

bash
$ git clone https://github.com/BishopFox/sj.git
$ cd sj/
$ go build .

Installing the latest version is a single go install, and the note about the PATH is the part people miss on a fresh machine:

bash
$ go install github.com/BishopFox/sj@latest

# Note: you may also need to place the path to your Go binaries within your PATH environment variable:
$ export PATH=$PATH:~/go/bin

The module itself declares Go 1.25 in its go.mod and depends on kin-openapi for the OpenAPI parsing, cobra for the command line, yaml.v3 and fatih/color. The build also has a Dockerfile and a goreleaser configuration, and the container image is built on a distroless static base with the binary copied in and set as the entry point, so the released image contains the tool and nothing else.

What the automate output actually tells you

The automate command sends a series of requests to each defined endpoint and analyses the status code of each response, and the output is a list of method, status and path with a symbol in front of each line. A tick means a 200, and a warning sign marks the ones that did not come back clean:

bash
$ sj automate -u https://petstore.swagger.io/v2/swagger.json -qi -p http://127.0.0.1:8080               

The distinction to hold on to is between a 200, a 500 and the N/A entries, because they mean different things. A 200 on an endpoint that should require authentication is the finding you are looking for. A 500 is a server error, which usually means the request was rejected in a way the tool could not interpret as an authentication result. An N/A means the request was not sent, and the examples show it on endpoints that need a file upload or a body the tool could not synthesise. So the output is not a pass and fail list, it is a triage list where you have to read what each status means, and the verbose flag is there to show the partial or full response body for the ones you want to look at.

Separating the scan from the interception proxy

The flag that makes sj usable in a real workflow is --replay-proxy. It lets you replay matched requests through a separate proxy, for example Burp Suite, and the point of the design is that you can route all traffic through one proxy, or directly, while only sending the interesting results to your interception proxy. The plain invocation sends scanning traffic to the target and the replay traffic to the interception proxy:

bash
$ sj automate -u https://petstore.swagger.io/v2/swagger.json -qi -p http://proxy:9090 --replay-proxy http://127.0.0.1:8080

That separation is what stops a scan from filling your proxy history with thousands of uninteresting requests, since only the requests worth looking at reach Burp. The verbose flag works the same way, adding the partial or full response under each line, which is how you tell a 200 that returned a valid-looking body from a 200 that returned an empty one. It is worth remembering that the tool is sending real requests against a live API, so the auditing is not a static read of the definition file. The statuses it reports are the statuses the server actually returned.

prepare hands the work back to you

The prepare command does the opposite of automate, generating a list of commands to use for manual testing, and it currently supports both curl and sqlmap, with the expectation that you will have to modify them slightly. The output is one ready-made request per endpoint, with the path values filled in from the definition:

bash
$ sj prepare -u https://petstore.swagger.io/v2/swagger.json -qi -p http://127.0.0.1:8080

The modification caveat is the point of the command rather than a defect. A generated curl is a starting point with a plausible body, and what you actually want to send to a given endpoint depends on what the endpoint does and what a valid request looks like, which is exactly the judgement a script cannot make for you. The sqlmap option is there for the endpoints that take a parameter and might have an injection flaw, and the two choices cover the common cases of an audit where you are looking for missing authentication and for a parameter that is handled unsafely. The endpoints subcommand is the most conservative of the three, since it only lists the raw routes and leaves path values unreplaced.

brute is the one that ignores your definition file

The brute subcommand sends a series of requests to a target to find operation definitions based on commonly used file paths, and it is worth understanding why it is in the set and how it differs. Every other subcommand starts from a definition file you supply with the -u flag, which means the tool only knows about endpoints somebody already wrote down. That is a reasonable default for an audit of a documented API, but it misses exactly the case where the interesting endpoint is undocumented, or where the published definition is out of date. brute closes that gap by guessing, and the guessing is confined to commonly used file paths. That is the line to think about before using it, because it is the one mode where the tool is generating traffic at paths nobody documented rather than replaying a specification. The convert subcommand is the odd one out, since it works on the definition file alone and turns a v2 file into a v3 one, which is a compatibility helper for the file format rather than a testing mode.

The release cadence and what the repository looks like

The release history is steady, with 2.8.3 in October 2026, 2.8.2 in September and 2.8.1 in August, and the last push was on 2026-10-19. The licence is MIT. The repository itself is small and shaped like a Go command line application, with a main.go at the root, a cmd directory for the subcommands, a tests directory, the images for the readme, and the go.mod and go.sum files. The presence of a Dockerfile and a goreleaser configuration means the binaries for several platforms are produced by the release pipeline rather than by each user, and the distroless base in the container image is consistent with a security tool, since there is no shell and no package manager in the image that you could use to do anything else with it.

Editorial conclusion

sj suits a team that has published a Swagger or OpenAPI file and wants to know which of its endpoints answer requests that should have required authentication, and it suits an auditor who wants the request templates rather than a scanner that fires everything. It does not suit a job of finding endpoints nobody documented, since the tool starts from a definition file, and the brute subcommand is the one part of it that sends traffic without a specification to work from. Before you run it, point the scan at a target you are authorised to test, and read what the N/A entries in the output mean, since a request that was not sent is not a request that was rejected.

Frequently asked questions

What does sj do with a Swagger or OpenAPI file?

It parses the definition for paths, parameters and accepted methods, then hands the result to one of five subcommands: automate sends a series of requests and analyses the response status codes, prepare generates command templates for manual testing, endpoints lists the raw routes, brute sends requests to find operation definitions from commonly used file paths, and convert turns a v2 definition file into a v3 one.

How do I install and build sj?

Run go install github.com/BishopFox/sj@latest and make sure your Go binaries directory is on your PATH, which is usually ~/go/bin. To build from source you need Go 1.22.5 or newer, clone the repository and run go build inside it. The released container image is built on a distroless base with the binary as its entry point.

What does an N/A status mean in the sj automate output?

It means the request was not sent, which is different from a request that was rejected. The examples show N/A on endpoints that need a file upload or a body the tool could not synthesise, so those lines are untested rather than failed, and the verbose flag shows the response body for the ones that were actually requested.

What is the --replay-proxy flag for in sj?

It replays matched requests through a separate proxy such as Burp Suite, so you can route the scanning traffic through one proxy or directly while sending only the interesting results to your interception proxy. Combined with --proxy for the scan side, the two flags let you keep your Burp history readable.

Official sources

  1. BishopFox/sj on GitHub
  2. Issues
  3. License: MIT
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/bishopfox-sj.svg)](https://hysenlabs.com/projects/bishopfox-sj)

Was this useful?