Phishing Api Keys in Fastapi with Api Keys
Phishing Api Keys in Fastapi with Api Keys — how this specific combination creates or exposes the vulnerability
When an API key is transmitted in an insecure context, such as an unencrypted HTTP endpoint or within a query string that appears in logs and browser history, the key can be intercepted or inadvertently exposed. Phishing in this context does not target end-user credentials but instead targets developers and operators through social engineering or compromised documentation and channels. An attacker may distribute a malicious OpenAPI specification, a fake SDK, or a poisoned configuration that instructs clients to send their API key to an attacker-controlled endpoint. Because the API key is often embedded in client-side code or automation scripts, a single compromised template or repository can lead to widespread leakage across services.
FastAPI applications that rely solely on API keys via fastapi.security.ApiKey typically validate the key’s presence and value, but they do not automatically enforce transport integrity or contextual usage constraints. If the application does not reject requests that do not use TLS, an attacker performing passive sniffing or a man-in-the-middle on a misconfigured network can capture the key. Additionally, if the key is logged at the framework level—such as via custom dependencies that print the received header for debugging—keys can end up in centralized log stores that are accessible to unauthorized parties. In a supply-chain scenario, a compromised third-party client library or CI/CD artifact may exfiltrate keys by redirecting authentication calls, effectively turning legitimate API usage into a phishing vector.
The interplay with OpenAPI/Swagger analysis is important here: middleBrick cross-references spec definitions with runtime behavior to detect mismatches, such as an endpoint declaring securitySchemes with an API key but serving responses over non-HTTPS in practice. Such inconsistencies increase the risk that a key will be transmitted in clear text or to an unintended host. Because API keys are often long-lived credentials used across multiple services, exposure through phishing or misconfigured documentation allows an attacker to pivot internally, escalate privileges, or gain unauthorized access to protected resources without triggering per-request authentication challenges.
Api Keys-Specific Remediation in Fastapi — concrete code fixes
Remediation focuses on enforcing transport security, reducing exposure in logs, and validating the context in which API keys are accepted. The following code examples demonstrate secure patterns for using API keys in FastAPI.
1. Enforce HTTPS-only API key transmission
Ensure that your FastAPI application rejects non-TLS requests when API keys are in use. Use middleware or a dependency to verify the request’s TLS state in production.
from fastapi import FastAPI, Request, HTTPException
from fastapi.security import ApiKeyHeader
import os
app = FastAPI()
api_key_header = ApiKeyHeader(name="X-API-Key", auto_error=False)
@app.middleware("http")
async def enforce_https(request: Request, call_next):
if os.getenv("ENVIRONMENT") == "production" and not request.url.scheme == "https":
raise HTTPException(status_code=403, detail="HTTPS required")
response = await call_next(request)
return response
async def get_api_key(request: Request):
key = api_key_header(request)
if not key:
raise HTTPException(status_code=403, detail="API key missing")
# Avoid logging the key
return key
@app.get("/secure-endpoint")
async def secure_endpoint(api_key: str = Depends(get_api_key)):
return {"status": "ok"}
2. Avoid logging API keys and sanitize error messages
Custom dependencies and middleware should never include raw keys in logs. Use structured logging that redacts sensitive headers, and ensure exceptions do not leak stack traces or key values.
import logging
from fastapi import Depends
logger = logging.getLogger(__name__)
def get_api_key_no_log(request: Request):
key = api_key_header(request)
if key is None:
logger.warning("API key header missing")
raise HTTPException(status_code=403, detail="Authentication failed")
logger.info("Authenticated request", extra={"redacted_header": True})
return key
3. Validate key format and scope against an allowlist
Do not accept arbitrary strings as API keys. Use a strict pattern and verify the key against a secure store with minimal leakage via timing differences.
import re
from typing import Optional
def validate_key_format(key: str) -> bool:
pattern = r"^AK[a-zA-Z0-9]{32}$"
return re.match(pattern, key) is not None
async def get_api_key_with_validation(request: Request):
key = api_key_header(request)
if not key or not validate_key_format(key):
raise HTTPException(status_code=403, detail="Invalid key format")
# Perform constant-time lookup to avoid timing attacks
if not await key_exists_and_active(key):
raise HTTPException(status_code=403, detail="Invalid key")
return key
4. Use security schemes in OpenAPI and keep docs consistent with reality
Define the security scheme explicitly and ensure runtime enforcement matches the spec. This reduces the chance that documentation or generated clients will instruct callers to use HTTP.
from fastapi import FastAPI
from fastapi.openapi.utils import get_openapi
app = FastAPI()
app.add_middleware(
CORSMiddleware,
allow_origins=["https://trusted-client.example.com"],
allow_credentials=True,
allow_methods=["GET", "POST"],
allow_headers=["X-API-Key"],
)
@app.get("/items/", dependencies=[Depends(api_key_header)])
async def read_items():
return [{"item_id": "abc"}]