Free tool
OpenAPI security linter
Lint an OpenAPI 3 or Swagger 2.0 document for the security problems that are visible in the spec itself.
Runs entirely in your browser
What this checks
- Whether any security schemes are defined at all
- Whether a global security requirement exists, and whether it names schemes that exist
- Operations that inherit no authentication requirement and are reachable unauthenticated
- State-changing operations explicitly marked with an empty security array
- API keys sent in the query string, and HTTP Basic authentication
- OAuth2 flows that declare no scopes, and servers listed over plain http
Your data stays in this tab
This tool runs as JavaScript in your browser. Whatever you paste is read by the page and analysed locally — it is never uploaded, logged or stored, and the tool does not send any request to the API you are inspecting. Close the tab and it is gone.
What the linter looks at
An OpenAPI document is the closest thing many teams have to a security model for their API. It records which operations need which credential, which credential is sent where, and which endpoints deliberately have none. That makes it worth checking as a document — a gap in the spec is usually a gap in the implementation, because the spec is what the implementation is built from.
Schemes and where the key travels
An apiKey scheme has an in field, and that field decides how exposed the key is. header is the right answer. query puts the key into every access log on the path, and cookie means it is attached to every request automatically — which is fine if the cookie isHttpOnly, Secure and SameSite, and a problem if it is not.
Global versus per-operation security
The top-level security block is the default for the whole API. Each operation can override it, and an operation can override it with an empty array — security: [] — which explicitly declares that the operation needs no credential. On aGET that is often a public endpoint. On aPOST, PUT, PATCH orDELETE it is the shape of a broken access control finding, and the linter treats it as one.
What the document cannot tell you
Everything here is read from the spec. The linter cannot tell you whether the server enforces what the spec claims, whether the scopes in an OAuth2 flow are checked against the caller's actual permissions, or whether an object-level authorisation check exists behind an endpoint that looks fine in the document. Those need the scanner.
A worked example
Linting this document finds three failures:
openapi: 3.0.3
info:
title: Example API
version: 1.0.0
servers:
- url: https://api.example.com
components:
securitySchemes:
apiKeyAuth:
type: apiKey
in: query
name: api_key
security:
- apiKeyAuth: []
paths:
/users:
get:
responses:
'200':
description: ok
post:
security: []
responses:
'201':
description: created- The API key is defined with
in: query, so every credential it issues is written into access logs and browser history. POST /userssetssecurity: [], declaring that creating a user requires no credential at all.- The
POSToperation documents no401or403response, so a client has no documented way to tell an authorisation failure apart from any other error.
Moving the key to a header, giving the POST the same security requirement as the rest of the API, and documenting the error responses clears all three.
Questions
Does the linter read a live API?
No. It reads the specification document you give it — a pasted string or a file you choose from disk. It never fetches a URL, never loads the remote spec and never contacts the API the document describes.
Does it check whether the API is actually secure?
No. It checks the security declared in the document, which is a useful proxy but not the same thing. A document can declare authentication on every operation while the server ignores it, or it can declare none while the server enforces a session cookie it was never told about. What it does give you is a fast way to find the places where the declared security is missing, inconsistent or written in a way that invites mistakes.
What is the difference between a global security block and a per-operation one?
The global block applies to every operation that does not override it, which is usually what you want: one definition of how the API is authenticated, with exceptions where they are needed. A per-operation block overrides it. The sharp edge is the empty array — "security: []" explicitly removes the global requirement for that operation, and on a state-changing operation that is usually a mistake rather than an intention.
Why is an API key in a query string reported as a failure?
Because query strings end up in more places than people expect: browser history, server access logs, proxy and CDN logs, error reports, and the Referer header sent to the next site the user visits. Any of those is a place a credential should not be. The OWASP API Security guidance puts it plainly: send the key in a header instead.
Does it support Swagger 2.0?
It parses it and reports it, but it tells you Swagger 2.0 is no longer maintained and several security features it lacks are only available in OpenAPI 3. If you have a Swagger 2.0 document, migrating it is worth the effort.
Get EndpointCheck when it launches
We're building automated API security scanning for teams that ship REST APIs. It isn't live yet. Join the waitlist and we'll email you once when it is.