Swagger exposed secrets
Theory
Why This Matters
Exposed API documentation is one of the most consistently productive reconnaissance steps in web application penetration testing. In a 2022 PortSwigger research scan of Fortune 500 companies, over 30% had Swagger UI exposed in production with no authentication requirement. Exposed documentation has directly contributed to breaches: in 2021, a major financial institution's internal fund transfer API was discovered via an exposed OpenAPI spec, which documented a /internal/transfer/bulk endpoint with no mention of authentication requirements — an endpoint that proved to be accessible with standard user credentials. GraphQL introspection, the GraphQL equivalent of Swagger, was enabled in production at multiple major platforms including GitLab (where it enabled mapping of internal data relationships). The OWASP API Security Top 10 2023 lists "Improper Inventory Management" (API9) as a top-10 risk, encompassing undocumented and documentation-exposed endpoints.
Core Concept
API documentation formats — Swagger 2.0, OpenAPI 3.x, RAML, API Blueprint — describe every endpoint, parameter, request schema, and response schema of an API. When served publicly in a production environment, this documentation provides an attacker with a complete map of the attack surface without requiring any reverse engineering.
Standard documentation paths that tools probe by default:
/swagger-ui.html,/swagger-ui,/swagger-ui//api-docs,/api-docs/,/v2/api-docs,/v3/api-docs/openapi.json,/openapi.yaml,/openapi/swagger.json,/swagger.yaml/.well-known/openapi/api/swagger-ui.html,/api/openapi.json/docs,/redoc(ReDoc renderer)
Sensitive information exposed in documentation:
- Undocumented or internal endpoints — endpoints prefixed
/internal/,/admin/,/debug/,/v0/that are not linked from the UI but appear in the OpenAPI spec. - Example values containing real credentials — developers copy-paste real API keys, tokens, or passwords into the
examplefields of request schemas. - Security scheme definitions — the
securityDefinitionsblock may reveal authentication mechanisms including JWT signing algorithms, OAuth scopes, and API key header names, enabling targeted attacks. - Deprecated endpoint versions —
/api/v1/endpoints that are documented as deprecated may lack the security controls added to/api/v2/(e.g., the authorization check was added only in v2). - Parameter names enabling injection — parameter names that suggest SQL (
table,query,filter,order), file operations (path,file,template), or command execution (cmd,exec,command) are injection candidates.
robots.txt as a negative indicator: Disallow: /swagger-ui in robots.txt indicates the path exists and the operator knows it, but relies on crawlers to honor the rule — a finding that confirms the path should be tested.
GraphQL introspection is the semantic equivalent: {"query": "{ __schema { types { name fields { name } } } }"} returns the complete type system of the GraphQL API, equivalent to an OpenAPI spec.
Technical Deep-Dive
# ── Automated Swagger/OpenAPI path probing ────────────────────────────────
# Using ffuf with a documentation path wordlist
ffuf -w /usr/share/seclists/Discovery/Web-Content/swagger.txt
-u "https://api.example.com/FUZZ"
-mc 200,301,302
-o swagger_fuzz_results.json
# Common paths to check (quick manual list)
PATHS=(
"/swagger-ui.html"
"/swagger-ui"
"/api-docs"
"/v2/api-docs"
"/v3/api-docs"
"/openapi.json"
"/openapi.yaml"
"/swagger.json"
"/docs"
"/redoc"
"/api/swagger-ui.html"
"/api/openapi.json"
)
for path in "${PATHS[@]}"; do
STATUS=$(curl -s -o /dev/null -w "%{http_code}" "https://api.example.com${path}")
[ "$STATUS" = "200" ] && echo "[+] FOUND: ${path} (${STATUS})"
done
# ── Parse an OpenAPI spec for sensitive endpoints and example values ────────
python3 - <<'EOF'
import json, sys, re
with open("openapi.json") as f:
spec = json.load(f)
# Extract all paths
print("=== All Endpoints ===")
for path, methods in spec.get("paths", {}).items():
for method in methods:
security = methods[method].get("security", "INHERITED")
print(f" {method.upper()} {path} security={security}")
# Find suspicious paths (internal, admin, debug)
print("
=== Suspicious Endpoints ===")
for path in spec.get("paths", {}):
if any(kw in path.lower() for kw in ["internal", "admin", "debug", "v0", "hidden", "test"]):
print(f" [!] {path}")
# Find example values that look like credentials
print("
=== Possible Credentials in Examples ===")
spec_str = json.dumps(spec)
# API key patterns
for m in re.finditer(r'(sk|pk)_(live|test)_[A-Za-z0-9]{20,}', spec_str):
print(f" [!] Stripe-like key: {m.group()}")
for m in re.finditer(r'AKIA[0-9A-Z]{16}', spec_str):
print(f" [!] AWS access key: {m.group()}")
for m in re.finditer(r'"(api.?key|token|secret|password)"s*:s*"([^"]{8,})"', spec_str, re.IGNORECASE):
print(f" [!] Possible credential — field={m.group(1)} value={m.group(2)}")
EOF
# ── Test all documented endpoints with low-privilege token ────────────────
import requests, json
with open("openapi.json") as f:
spec = json.load(f)
base_url = "https://api.example.com"
headers = {"Authorization": "Bearer LOW_PRIVILEGE_TOKEN", "Content-Type": "application/json"}
results = []
for path, methods in spec.get("paths", {}).items():
for method, details in methods.items():
if method.lower() in ("get", "post", "put", "delete", "patch"):
# Replace path parameters with test values
test_path = path.replace("{id}", "1").replace("{userId}", "1")
.replace("{uuid}", "00000000-0000-0000-0000-000000000001")
try:
resp = getattr(requests, method.lower())(
f"{base_url}{test_path}",
headers=headers,
json={},
timeout=10,
)
results.append({
"method": method.upper(),
"path": path,
"status": resp.status_code,
"length": len(resp.content),
})
if resp.status_code not in (401, 403, 404):
print(f"[!] Accessible: {method.upper()} {path} → {resp.status_code}")
except Exception as e:
pass
# ── GraphQL introspection ──────────────────────────────────────────────────
introspection_query = """{
__schema {
types { name kind fields { name type { name kind } } }
queryType { fields { name description args { name type { name } } } }
mutationType { fields { name description } }
}
}"""
r = requests.post(
f"{base_url}/graphql",
json={"query": introspection_query},
headers=headers,
)
if r.status_code == 200 and "__schema" in r.text:
print("[+] GraphQL introspection enabled — full schema retrieved")
schema = r.json()["data"]["__schema"]
print(f" Types: {len(schema.get('types', []))}")
print(f" Queries: {len(schema.get('queryType', {}).get('fields', []))}")
Security Assessment Methodology
- Probe all standard documentation paths — Use ffuf with a Swagger/OpenAPI path wordlist (SecLists:
Discovery/Web-Content/swagger.txt). Include both authenticated and unauthenticated requests, as some deployments expose docs only to authenticated users. - Check
robots.txtandsitemap.xml— Documentation paths inDisallowrules or sitemaps confirm existence. Request them directly. - Download and parse the OpenAPI/Swagger spec — Retrieve the JSON or YAML spec. Parse all
pathskeys. Flag endpoints with suspicious names (/internal/,/admin/,/debug/,/v0/). Extract allexamplevalues and scan for credential patterns. - Test all documented endpoints with a low-privilege token — Use the Python script above to systematically request every endpoint. Flag any that return
200,201, or500(which indicates the endpoint exists and was reached). - Test GraphQL introspection — Submit
{"query": "{ __schema { types { name } } }"}to/graphql,/api/graphql,/query. If introspection is enabled, retrieve the full schema. - Verify security of deprecated versions — If
/api/v1/and/api/v2/are both documented, test security controls on v1 endpoints. Missing authorization checks in deprecated versions are common. - Review security scheme definitions — The
securityDefinitionsorcomponents/securitySchemesblock reveals authentication mechanisms. Weak JWT algorithms (none,HS256with guessable secrets) discovered here guide subsequent JWT attacks.
Defensive Countermeasure — Disable or require authentication for all API documentation endpoints in production deployments. In Spring Boot: set
springfox.documentation.swagger-ui.enabled=falsein production profiles. In FastAPI:app = FastAPI(docs_url=None, redoc_url=None)in production. Disable GraphQL introspection in production (introspection: falsein Apollo Server). Never include real credentials in OpenAPI example values; use clearly synthetic values (YOUR_API_KEY,example_token). Use environment-conditional documentation serving: only enable docs in development and staging environments.
Common Assessment Errors
- Only checking
/swagger-ui.html— Modern frameworks use many different default paths. Always probe the full wordlist; ReDoc (/redoc), Stoplight (/docs), and custom paths are common alternatives. - Missing authentication on documentation as a separate finding — Even if no sensitive information is found in the spec, unauthenticated access to API documentation in production is itself a finding (information disclosure / security misconfiguration).
- Not testing deprecated API versions — v1 endpoints documented alongside v2 are frequently forgotten in security reviews and lack v2's authorization improvements.
- Skipping GraphQL introspection — If the application uses GraphQL, introspection is the equivalent of Swagger exposure and must be tested.
- Not scanning example values for credentials — Developers frequently paste real keys into examples during development and forget to replace them. This is a consistently productive check.
- Testing endpoints only as unauthenticated — Some documentation is accessible only to authenticated users. Always test both with and without a session token.
NICE Framework Alignment
| Code | Knowledge/Skill/Task Statement | How This Card Develops It |
|---|---|---|
| K0007 | Knowledge of authentication, authorization, and access control methods | Explains how documentation exposure reveals authentication schemes and gaps in coverage |
| K0065 | Knowledge of policy-based controls for data access | Connects environment-conditional documentation serving to production security policy |
| K0070 | Knowledge of system and application security threats and vulnerabilities | Maps Swagger exposure to OWASP API9 and real-world internal endpoint discovery incidents |
| S0001 | Skill in conducting vulnerability scans and recognizing vulnerabilities in security systems | Trains systematic path probing with ffuf and programmatic spec parsing |
| T0028 | Conduct and support authorized penetration testing on enterprise networks | Provides a tool-explicit methodology from path discovery through endpoint authorization testing |
| T0570 | Conduct application security assessments | Frames API documentation discovery as a required step in every API security assessment |
Further Reading
- OWASP API Security Top 10 2023, API9: Improper Inventory Management — OWASP Foundation
- SecLists: Discovery/Web-Content/swagger.txt — Daniel Miessler (GitHub, offline reference)
- "GraphQL Introspection in Production" — Apollo GraphQL Security Documentation
Challenge Lab
Reinforce your learning with a hands-on generated challenge based on this card's competency.