Swagger and OpenAPI Security Testing: Finding Vulnerabilities via API Specs

An exposed OpenAPI specification is a complete map of your API surface. Every endpoint, every parameter, every authentication requirement — documented and machine-readable. For legitimate users, this is convenience. For a security tester (or an attacker), it is reconnaissance that would otherwise take hours condensed into a single JSON file.

This guide covers how to find OpenAPI and Swagger specifications on your targets, what to look for when you have one, how to use the spec to drive security testing at scale, and the specific vulnerability classes that appear most consistently when API documentation is used as a testing guide.

Finding API Specifications

Many applications expose their API specs without authentication — either intentionally (public developer documentation) or by accident (internal APIs deployed with default settings). Common locations:

# OpenAPI v3 common paths
/openapi.json
/openapi.yaml
/api/openapi.json
/v1/openapi.json
/v2/openapi.json
/api-docs
/api-docs.json
/api/v1/api-docs

# Swagger v2 common paths
/swagger.json
/swagger.yaml
/swagger/v1/swagger.json
/swagger/v2/swagger.json
/api/swagger.json
/api/swagger
/swagger-ui.html
/swagger-ui/
/swagger-ui/index.html

# Framework-specific defaults
/v2/api-docs          # Spring Boot (springdoc-openapi)
/v3/api-docs          # Spring Boot (springdoc-openapi v3)
/__swagger__/
/redoc
/rapidoc

# Developer portals
/developer
/developer/api
/docs/api
/api-reference

Use a tool like ffuf or dirsearch with an API-focused wordlist to automate discovery:

ffuf -u https://target.com/FUZZ -w api-spec-paths.txt -mc 200,301,302 -t 50

# Or with curl — test common paths in a loop:
for path in swagger.json openapi.json api-docs v3/api-docs swagger/v1/swagger.json; do
    status=$(curl -s -o /dev/null -w "%{http_code}" https://target.com/$path)
    echo "$status  $path"
done

Analysing the Specification

Extracting All Endpoints

Once you have the spec, extract every endpoint and method combination. This gives you a definitive list of attack surface:

import json, sys

with open('openapi.json') as f:
    spec = json.load(f)

for path, methods in spec.get('paths', {}).items():
    for method, details in methods.items():
        auth = 'security' in details or 'security' in spec
        print(f"{method.upper():8} {path:50} auth={auth}")
# With jq from the command line:
cat openapi.json | jq -r '.paths | to_entries[] | .key as $path | .value | to_entries[] | "\(.key | ascii_upcase) \($path)"'

Security Schemes and Authentication Gaps

The spec's securitySchemes and per-endpoint security definitions reveal what authentication is supposed to be required. Mismatches between documented requirements and actual enforcement are common:

# Check which endpoints have no security requirement defined
cat openapi.json | jq -r '
  .paths | to_entries[] |
  .key as $path |
  .value | to_entries[] |
  select(.value.security == null or .value.security == []) |
  "\(.key | ascii_upcase) \($path) — NO SECURITY DEFINED"
'

Look specifically for:

Testing with the Specification as a Guide

Authentication Bypass Testing

For every endpoint that requires authentication per the spec, test without credentials and with invalid credentials:

#!/bin/bash
# Extract authenticated endpoints and test unauthenticated
BASE="https://target.com"
TOKEN="your_valid_token"

# Test without token
curl -s -o /dev/null -w "%{http_code} GET /api/users/me\n" $BASE/api/users/me
# Expect: 401 or 403

# Test with tampered token
curl -s -H "Authorization: Bearer invalid.token.here" \
  -o /dev/null -w "%{http_code} GET /api/users/me (bad token)\n" \
  $BASE/api/users/me
# Expect: 401

Parameter Fuzzing with Schema Information

The schema definitions tell you exactly what input the API expects — which is exactly what to violate during security testing:

# If spec defines: username: {type: string, maxLength: 20}
# Test with 21 characters, then 1000 characters, then injection payloads
# If spec defines: age: {type: integer, minimum: 0, maximum: 150}
# Test with -1, 0, 151, 999999, "string", null, []
# If spec defines: role: {type: string, enum: ["user", "admin"]}
# Test with "superadmin", "root", null, and missing the field entirely

Tools that automate spec-driven fuzzing:

## schemathesis — spec-driven property-based testing
pip install schemathesis
schemathesis run https://target.com/openapi.json --auth "Bearer $TOKEN"

# Or against a local spec with custom target:
schemathesis run openapi.json --base-url https://target.com/api --auth "Bearer $TOKEN"

## RESTler — intelligent REST API fuzzing from Microsoft Research
# Generates test sequences from OpenAPI specs
./Restler compile --api_spec openapi.json
./Restler fuzz --grammar_file Compile/grammar.py --target_ip target.com --target_port 443

Information Disclosure in API Specs

Beyond using the spec as a testing guide, the spec itself is a finding when exposed without authentication. Review it for:

Internal Infrastructure References

# Servers object may reveal internal hostnames
cat openapi.json | jq '.servers'

# Look for internal URLs in examples, descriptions, or x- extensions
cat openapi.json | grep -E "(internal|localhost|10\.|192\.168\.|172\.|\.internal|\.corp)"

Sensitive Data Schemas

# Schema property names reveal data model
cat openapi.json | jq -r '.. | .properties? // empty | keys[]' | sort -u | \
  grep -iE "(password|secret|token|key|ssn|credit|card|cvv|pin|dob|salary)"

Deprecated Endpoints Still Active

# Find deprecated endpoints in spec
cat openapi.json | jq -r '
  .paths | to_entries[] |
  .key as $path |
  .value | to_entries[] |
  select(.value.deprecated == true) |
  "\(.key | ascii_upcase) \($path)"
'
# Then test if deprecated endpoints still respond
# Deprecated ≠ removed; they often have weaker controls

BOLA/IDOR via Spec Analysis

OpenAPI specs reveal object identifier patterns used in paths. These are direct tests for broken object-level authorization (BOLA/IDOR):

GET /api/users/{userId}/documents/{documentId}
GET /api/orders/{orderId}
GET /api/invoices/{invoiceId}/download
POST /api/admin/users/{userId}/disable

For every endpoint with a path parameter referencing an object ID:

  1. Authenticate as User A and create or retrieve a resource — get its ID
  2. Authenticate as User B
  3. Attempt to access User A's resource using User B's credentials
  4. Check for cross-tenant access (if multi-tenant)
  5. Test sequential IDs, GUIDs, and other ID patterns visible in the spec

Mass Assignment from Schema Definitions

Request body schemas list every accepted property. Compare the documented writable properties against what the server actually processes:

# If POST /api/users schema includes: {name, email, role, isAdmin}
# But the application should only accept {name, email} from regular users
# Test sending role=admin or isAdmin=true in the request body

curl -X POST https://target.com/api/users \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $USER_TOKEN" \
  -d '{"name": "Test", "email": "test@test.com", "role": "admin", "isAdmin": true}'

API Version Testing

When a spec defines multiple server versions or you find versioned paths, older versions are high-value targets:

GET /api/v1/admin/users     # May lack auth checks added in v2
GET /api/v2/admin/users     # Current version with proper controls
GET /v1/openapi.json        # Old spec may document removed endpoints

# Test if v1 endpoints accept v2 tokens and bypass v2 controls
# Test if deprecated v1 endpoints still respond with reduced security
# Check if v1 returns more fields in responses (information disclosure)

Importing Specs into Testing Tools

Tool How to Import OpenAPI Spec Use Case
Burp Suite Target → Site Map → right-click → OpenAPI definition Auto-populate site map and scanner with all endpoints
Postman Import → OpenAPI 3.0 or Swagger 2.0 Generate collection for manual testing
OWASP ZAP Import → OpenAPI Definition Spider entire API surface, run active scan
schemathesis CLI: schemathesis run openapi.json Property-based fuzzing of all endpoints
Nuclei nuclei -u target.com -t openapi.yaml Template-based testing of spec-defined endpoints

Ironimo automatically discovers OpenAPI and Swagger specifications during scanning, uses them to enumerate and test every documented endpoint, and identifies discrepancies between what the spec claims is protected and what the API actually enforces. The spec is a map — Ironimo uses it as one.

Start free scan
← Back to Blog