FastAPI: OpenAPI Exposure and API Reconnaissance Risks
At 2:13 AM on a Tuesday, the on-call engineer at a fintech startup noticed something strange: thousands of requests hitting internal-looking API routes that were never meant for public users.
The company had built its backend with FastAPI. During development, the team loved the automatic /docs and /openapi.json features because frontend developers could instantly test APIs.
But nobody disabled them in production.
A threat actor running automated crawlers scanned the internet for exposed openapi.json files. Within minutes, they discovered the startup’s API schema — every endpoint, request model, response structure, authentication header, admin route, and even deprecated internal APIs still active in production.
One endpoint stood out:
/internal/export/customer-financials
It was intended only for an internal dashboard and protected by a weak API key check copied from staging.
The attacker used the OpenAPI spec to understand the exact request format, required headers, pagination structure, and response fields without any reverse engineering. They scripted requests overnight and quietly extracted:
- customer PAN details
- transaction histories
- KYC documents
- internal account notes
- partial card metadata
Because the requests looked syntactically valid, the WAF never flagged them.
Three weeks later, customers reported identity theft and unauthorized loan applications.
During the incident review, the security team concluded:
“The breach was accelerated because the attacker had a complete machine-readable map of the platform through the exposed OpenAPI schema.”
The company spent months handling:
- regulatory investigations
- mandatory breach disclosures
- customer compensation
- SOC 2 audit failures
- reputational damage
All triggered by a feature developers assumed was “harmless documentation” and “So called Authorized APIs”
The API itself is “authorized,” but the surrounding implementation is weak.
For example:
- the API uses static API keys instead of short-lived tokens
- old staging credentials still work in production
- rate limiting is missing
- JWT validation is misconfigured
- internal roles are not properly enforced
- predictable secrets are used
- authentication exists, but authorization checks are weak
The exposed openapi.json makes exploitation dramatically easier because it gives attackers a blueprint of the system.
Get Darshita Paghadal’s stories in your inbox
Join Medium for free to get updates from this writer.
Example attack flow:
- Attacker finds:
https://company.com/openapi.json - They discover:
POST /internal/export/customer-financials
Header: X-API-KEY
Body:
{
"from_date": "string",
"to_date": "string"
}
The schema also reveals: exact auth header name, request structure, expected response, error messages, admin-only endpoints and so on…
Now the attacker knows, this endpoint exists and it uses API-key auth with valid requests look like.
Attackers will try common failures:
- leaked staging keys from GitHub
- old employee credentials
- weak hardcoded secrets
- brute-force against poorly rate-limited keys
- JWT alg confusion
- IDOR vulnerabilities
- missing role checks
Without OpenAPI exposure, they would first need to reverse-engineer endpoints manually.
With it exposed, reconnaissance becomes trivial and highly automated.
That is why public Swagger/OpenAPI exposure in production is considered dangerous for private/internal APIs — not because OpenAPI itself is vulnerable, but because it massively reduces attacker effort and exposes attack surface intelligence.
Protecting FastAPI Docs with Authorization
FastAPI’s interactive documentation at /docs and /redoc is a powerful tool, but leaving it public in production can expose a complete map of your API's architecture. By default, anyone with the URL can see every endpoint and data model.
This guide covers how to disable the default documentation and replace it with protected endpoints that require a valid token.
Step 1: Disable the Default Documentation
Initialize your FastAPI app with docs_url, redoc_url, and openapi_url set to None. This stops the framework from automatically mounting the public documentation routes:
python:
from fastapi import FastAPI
app = FastAPI(
title="My Secure API",
docs_url=None,
redoc_url=None,
openapi_url=None
)Step 2: Create a Protected Router
Instead of the global app, we use a separate APIRouter for documentation and apply a security dependency like HTTPBearer or OAuth2PasswordBearer.
python:
from fastapi import APIRouter, Depends, HTTPException, status
from fastapi.openapi.docs import get_swagger_ui_html
from fastapi.openapi.utils import get_openapi
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
# Replace with your actual JWT/Token validation logic
from .auth import validate_token
router = APIRouter()
security = HTTPBearer()
async def get_current_user(auth: HTTPAuthorizationCredentials = Depends(security)):
if not validate_token(auth.credentials):
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Invalid or missing token",
)
return True
@router.get("/openapi.json", include_in_schema=False)
async def get_open_api_endpoint(authorized: bool = Depends(get_current_user)):
return get_openapi(
title=app.title,
version=app.version,
routes=app.routes,
)
@router.get("/docs", include_in_schema=False)
async def get_documentation(authorized: bool = Depends(get_current_user)):
return get_swagger_ui_html(
openapi_url="/openapi.json", # Point to your protected JSON endpoint
title=app.title + " - Swagger UI",
)Step 3: Include the Router in Your App
Add the new router to your main app instance.
python
app.include_router(router)How it Works
- Authorization Required: When you visit
/docs, your browser will prompt for a token (if using Basic Auth) or require one in theAuthorizationheader. - Schema Protection: If a user tries to access
/openapi.jsondirectly without a token, theget_current_userdependency will block the request with a401 Unauthorizedstatus. - UI Integration: The
get_swagger_ui_htmlfunction renders the interface only after the initial route dependency is satisfied that is token generation
4. Token: Token is generated and swagger documentations that is /docs url will be automatically accessible.
At the End,
An exposed openapi.json may look harmless, but in production it can become a complete reconnaissance map for attackers.
API security is not just about authentication — it is also about limiting visibility into your internal attack surface. There other ways also like short lived token, rate limit, role based access etc.. would like to keep it another day’s story..
Let’s comment whether it is helpful or not..






