OpenAPI and Security Audits: What Auditors Really Want to See
AI generated
{ }
GET
REST API · OpenAPI · Security Audit · OWASP
OpenAPI and Security Audits
what auditors really want to see

Security auditors open an OpenAPI document with a clear checklist in mind: are all endpoints authenticated? Are error responses fully documented? Is input validated? Whoever understands this perspective builds API documentation that speeds up audits, reduces findings, and builds trust.

16 min read Security Schemes · Error Responses · Input Validation · OWASP OpenAPI 3.x · OWASP API Security Top 10

1. The audit perspective: what auditors look for first

A security auditor who receives an OpenAPI document does not start at the top and read through linearly. They carry a mental checklist derived from the most common API security problems, usually aligned with the OWASP API Security Top 10. The first thing they look at is the security configuration: are there security schemes at all? Are they defined globally or per endpoint? Which endpoints explicitly declare security: [], meaning no authentication protection?

The second thing they check is the response definitions: are 401 and 403 responses documented for all authenticated endpoints? Are 422 or 400 responses shown for validation failures? Missing responses are not a cosmetic problem, they signal that the API may not handle validation errors correctly and could potentially leak sensitive information in error messages.

The third thing they check is the schemas: are integer fields defined without minimum/maximum? Strings without maxLength? Arrays without maxItems? These gaps in input validation documentation hint at possible injection attack vectors. An OpenAPI document that fills these fields in completely significantly reduces the auditor's workload and shows that the development team is familiar with the relevant security requirements.

2. Security schemes: the first field checked

The security scheme setup is the first thing an auditor analyzes in detail. Missing security schemes on endpoints that return user data are an immediate high-severity finding. Schemes that are too weak (e.g. HTTP Basic Auth without enforced TLS) or schemes without an expiration mechanism (e.g. API keys without rotation documentation) are medium-severity findings. An auditor expects the OpenAPI documentation to contain this information explicitly, not to have to look it up in the runtime configuration.

Particularly critical: endpoints that perform sensitive operations (changing a password, retrieving payment data, admin functions) should explicitly signal higher requirements in the documentation, for example through specific scopes or a description that documents MFA requirements. OpenAPI itself has no MFA type, but the security scheme's description field and the endpoint description are the right place for it.


# Security-focused OpenAPI, what auditors want to see
openapi: 3.1.0
info:
  title: Shop API, Security Documented
  version: 2.0.0
  description: |
    ## Security Overview

    This API uses JWT Bearer authentication for all endpoints.
    Tokens expire after 3600 seconds. Refresh tokens expire after 7 days.
    All endpoints enforce TLS 1.2+. Rate limiting: 100 requests/minute per token.

    ## Sensitive Operations
    Endpoints under /admin require the admin:* scope.
    Password-change endpoints require re-authentication within the last 5 minutes.

# Global security, explicitly set, not implied
security:
  - BearerAuth: []

components:
  securitySchemes:
    BearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT
      description: |
        JWT with RS256 signing. Claims: sub, roles, exp, iat, jti.
        Issued by: https://auth.mironsoft.de
        JWKS endpoint: https://auth.mironsoft.de/.well-known/jwks.json
        Token lifetime: 3600s. Refresh: POST /auth/refresh (7-day refresh token).
        Revocation: POST /auth/revoke (immediate effect via jti blacklist).

paths:
  /users/{id}/password:
    put:
      summary: Change user password
      description: |
        Requires re-authentication within the last 300 seconds.
        Returns 403 if the re-auth window has expired.
      security:
        - BearerAuth: []
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [currentPassword, newPassword]
              properties:
                currentPassword:
                  type: string
                  format: password
                  minLength: 8
                  maxLength: 128
                newPassword:
                  type: string
                  format: password
                  minLength: 12
                  maxLength: 128
                  description: Must contain uppercase, lowercase, digit and special char.
      responses:
        '204': { description: Password changed }
        '400': { description: Validation error, weak or malformed password }
        '401': { description: Missing or expired token }
        '403': { description: Re-auth window expired or wrong current password }
        '429': { description: Too many password-change attempts, try again in 15m }

3. Documenting public endpoints explicitly

Endpoints without authentication are not inherently a problem, health checks, public product listings, and login endpoints must be reachable without credentials. What auditors want to see is that these endpoints are deliberately and explicitly marked as public, not simply forgotten. An explicit security: [] combined with a description that explains why the endpoint is public shows that the API designer has thought through the security model.

A common audit finding: an endpoint that returns sensitive data (e.g. product prices including margin data) has no security scheme, not because it is meant to be public, but because it was forgotten. In an OpenAPI specification, this difference is not visible, both look like security: []. The solution is complete documentation of all public endpoints along with their justification in the description.

4. Modeling error responses completely

Complete error response definitions are one of the most telling signals in an OpenAPI specification from an audit perspective. An API that only documents the success case for every endpoint gives no indication of how it handles errors, and that is exactly what auditors want to know. Incomplete error responses hint at possible information disclosure problems: if the API has no defined error messages, it might be returning stack traces, database errors, or internal paths.

The minimum requirement from an audit standpoint: for every authenticated endpoint, 401 (missing token) and 403 (wrong permission) must be documented. For endpoints with input validation, 422 or 400 must be documented, including the schema of the error message. For admin endpoints, 404 instead of 403 should be considered (a security recommendation: for sensitive resources, respond with 404 rather than 403 on missing authorization, so as not to confirm their existence).


# Complete error responses, what auditors expect
components:
  schemas:
    # Standard error envelope, reused across all error responses
    ApiError:
      type: object
      required: [error]
      properties:
        error:
          type: object
          required: [code, message]
          properties:
            code:
              type: string
              description: Machine-readable error code (e.g. VALIDATION_FAILED)
              example: VALIDATION_FAILED
            message:
              type: string
              description: Human-readable error message. Never includes stack traces.
              example: The request body is invalid.
            details:
              type: array
              description: Field-level validation details (422 responses only)
              items:
                type: object
                required: [field, message]
                properties:
                  field: { type: string }
                  message: { type: string }

    # Rate limit error
    RateLimitError:
      allOf:
        - $ref: '#/components/schemas/ApiError'
        - type: object
          properties:
            retryAfter:
              type: integer
              description: Seconds until the rate limit resets

  responses:
    Unauthorized:
      description: Missing, invalid or expired authentication token.
      headers:
        WWW-Authenticate:
          schema: { type: string }
          example: 'Bearer realm="api.mironsoft.de", error="invalid_token"'
      content:
        application/json:
          schema: { $ref: '#/components/schemas/ApiError' }
          example:
            error: { code: INVALID_TOKEN, message: Token is expired or malformed. }

    Forbidden:
      description: Authenticated but insufficient permissions.
      content:
        application/json:
          schema: { $ref: '#/components/schemas/ApiError' }
          example:
            error: { code: INSUFFICIENT_SCOPE, message: Required scope not present in token. }

    UnprocessableEntity:
      description: Request body failed validation.
      content:
        application/json:
          schema: { $ref: '#/components/schemas/ApiError' }

    TooManyRequests:
      description: Rate limit exceeded.
      headers:
        Retry-After: { schema: { type: integer } }
        X-RateLimit-Limit: { schema: { type: integer } }
        X-RateLimit-Remaining: { schema: { type: integer } }
      content:
        application/json:
          schema: { $ref: '#/components/schemas/RateLimitError' }

5. Mapping input validation in OpenAPI

Input validation constraints in OpenAPI schemas are not just for documentation, they are a security signal to auditors. Fields without maxLength on string types, without maximum on integer types, or without maxItems on array types indicate that input limits may not be implemented at all. That is an attack surface for resource exhaustion attacks and injection attempts.

Particularly relevant from an audit perspective: format fields signal that specific format validation is taking place. format: email shows that email addresses are validated. format: uuid on ID fields shows that ID injection through integer enumeration is prevented. pattern on critical fields (e.g. phone numbers, postal codes) shows that regex validation is in use. Documenting all of these fields in OpenAPI schemas costs little effort but makes audits considerably more efficient.

6. Marking sensitive data in schemas

OpenAPI 3.1 (based on JSON Schema) has the writeOnly and readOnly keywords, which matter in security audits. Passwords, tokens, and other sensitive credentials should be marked as writeOnly: true, signaling that these fields only appear in the request body and are never returned in responses. Fields that appear in the response but never in the request (e.g. internal IDs, timestamps) should have readOnly: true.

The format: password keyword is also relevant: it indicates that the field contains a password and that tooling should treat it accordingly (e.g. masking in Swagger UI). Sensitive fields such as credit card numbers or social security numbers can be marked with a custom extension like x-sensitive: true, this extension has no native OpenAPI semantics, but it is a clear signal for security tooling and human reviewers.

7. OWASP API Security Top 10 and OpenAPI

The OWASP API Security Top 10 (2023) lists the most common API security problems and has direct counterparts in OpenAPI documents. API1 (Broken Object Level Authorization) can be addressed through complete documentation of 401/403 responses and explicit scope requirements per endpoint. API3 (Broken Object Property Level Authorization) is relevant in OpenAPI modeling: if different roles are allowed to see different fields, that should be documented through separate response schemas.

API8 (Security Misconfiguration) is the most common finding that can be derived directly from OpenAPI documents: missing security schemes, undocumented public endpoints, missing error responses. An auditor assessing API8 reads the OpenAPI document and compares it against the running API. Discrepancies between documentation and implementation are an immediate finding, the documentation is then either outdated or the implementation does not match the design.

OWASP API Finding OpenAPI Signal Addressed in OpenAPI Severity
API1: Broken Object Auth No 403 for endpoints with ID parameters Document 403 response + scope requirement High
API3: Excessive Data Exposure Response schema contains sensitive fields without readOnly Set writeOnly/readOnly + format: password correctly Medium
API4: Resource Exhaustion No maxLength/maxItems in schemas Consistently document constraints Medium
API8: Security Misconfiguration Missing security schemes or undocumented public endpoints Global security + explicit security: [] for public High

8. Rate limiting and quota in documentation

Rate limiting is not a native mechanism in OpenAPI 3.x, but auditors expect it to be documented. The recommendation: document rate limiting headers (X-RateLimit-Limit, X-RateLimit-Remaining, Retry-After) in the 429 response definitions. That shows auditors that rate limiting is implemented and that the API communicates it. Some teams use custom extensions like x-rate-limit: 100/min at the operation level, these have no native semantics but are a clear signal for security tools and auditors.

An often overlooked detail: different rate limits for different roles (e.g. 100 requests per minute for standard users, 1000 for premium) should be documented in the description of the endpoint or the security scheme. That prevents misunderstandings during testing and gives auditors the information they need to assess denial-of-service risks.


# Rate limiting, documented via responses and headers
paths:
  /products/search:
    get:
      summary: Search products
      description: |
        Rate limit: 100 requests/minute per authenticated token.
        Unauthenticated requests: 10 requests/minute per IP.
        Exceeding the limit returns 429 with Retry-After header.
      security:
        - BearerAuth: []
        - {}              # also allows unauthenticated (with lower rate limit)
      parameters:
        - name: q
          in: query
          required: true
          schema:
            type: string
            minLength: 2
            maxLength: 200    # prevent abuse via very long search queries
        - name: limit
          in: query
          schema:
            type: integer
            minimum: 1
            maximum: 100      # cap: prevent bulk scraping via high limit values
            default: 20
      responses:
        '200':
          description: Search results
          headers:
            X-RateLimit-Limit:
              description: Requests allowed per minute for this token/IP
              schema: { type: integer }
            X-RateLimit-Remaining:
              description: Requests remaining in current window
              schema: { type: integer }
            X-RateLimit-Reset:
              description: Unix timestamp when the rate limit window resets
              schema: { type: integer }
        '400':
          description: Query too short or too long
          $ref: '#/components/responses/UnprocessableEntity'
        '429':
          description: Rate limit exceeded
          $ref: '#/components/responses/TooManyRequests'

10. Summary

Security audits for REST APIs become considerably more efficient with complete OpenAPI documentation, and the number of findings drops. The most important outcome of careful, audit-oriented modeling: auditors spend less time figuring out how the API works and more time assessing whether it works securely. Fully defining security schemes, explicitly marking public endpoints, documenting error responses for all relevant status codes, and mapping input validation constraints into schemas, these are the four pillars of an audit-ready OpenAPI specification.

The long-term benefit goes beyond individual audits: an OpenAPI document that fully documents security requirements serves as a living security concept. New developers on the team immediately see which authentication, which scopes, and which error cases are expected. Automated security tools like 42Crunch or OWASP Zap can validate against the OpenAPI specification and automatically detect discrepancies between documentation and implementation.

OpenAPI Security Audit Readiness, At a Glance

Security Schemes

Fully documented: type, format, expiration, revocation. Global security object set. Public endpoints with explicit security: [] and justification.

Error Responses

401, 403, 422, 429 for all relevant endpoints. Consistent error schema without stack traces. WWW-Authenticate header for 401.

Input Validation

maxLength, minimum, maximum, maxItems for all input fields. format: uuid for IDs. format: password for credentials. writeOnly for sensitive fields.

OWASP Mapping

API1, API3, API4, API8 directly addressable through OpenAPI documentation. Automated validation with 42Crunch or OWASP Zap.

11. FAQ: OpenAPI and Security Audits

1What do auditors look at first?
Security scheme configuration and public endpoints with security: []. Then error responses: are 401 and 403 documented for all authenticated endpoints?
2Missing security scheme = high-severity finding?
Yes, for endpoints with sensitive data or write operations. For genuinely public endpoints, not a finding, if security: [] is documented with a justification.
3maxLength and maxItems for security?
Missing constraints suggest missing input limits, an attack surface for resource exhaustion. Documented constraints signal that the implementation enforces these limits.
4writeOnly for security?
Marks fields that only appear in the request, never in responses. Correct for passwords, tokens, credentials. Auditors expect this keyword on all sensitive input fields.
5403 or 404 on missing authorization?
404 for admin endpoints (prevents resource enumeration). 403 for regular user endpoints. Document the choice in the endpoint description, auditors expect this justification.
6Addressing OWASP API findings in OpenAPI?
API1 via 403 + scopes. API3 via writeOnly/readOnly. API4 via constraints. API8 via complete security scheme documentation and explicit public endpoints.
7Documenting rate limiting in OpenAPI?
429 response with Retry-After header. Rate limit headers in success responses. Custom x-rate-limit extension. Concrete limits in the endpoint description as text.
8Automatically checking OpenAPI for security?
42Crunch: static analysis specifically for OpenAPI security. OWASP Zap: dynamic tests using OpenAPI as an attack surface map. Spectral: custom linting rules.
9Marking credit card numbers in OpenAPI?
format: password for passwords. writeOnly: true for all sensitive input fields. Custom x-sensitive: true extension for data classification in security tools.
10OpenAPI and the running API diverge?
Immediate finding: documentation is outdated or implementation deviates from the design. Contract tests with Newman or Pact help detect discrepancies continuously.