Auth Bypass in Fastapi with Api Keys
Auth Bypass in Fastapi with Api Keys — how this specific combination creates or exposes the vulnerability
In FastAPI, using API keys via headers or query parameters without enforcing strict validation and scope separation can lead to an authentication bypass. This occurs when the application incorrectly trusts the presence of a key, does not validate it against a secure store on every request, or fails to bind the key to a specific authorization context. The API key mechanism itself is not inherently weak, but implementation choices determine whether an attacker can bypass intended access controls.
For example, if the key is read from request.headers or request.query_params but the route does not consistently require authentication (for instance, due to route-level dependency overrides or omitted dependencies on some paths), an unauthenticated caller may reach endpoints they should not. This violates the principle of explicit authorization checks and maps to the Broken Access Control (BAC) category in OWASP API Top 10. A real-world pattern seen in assessments is missing dependency enforcement where a key is retrieved but not validated before allowing downstream logic.
Another common vector is key leakage via logs, error messages, or client-side storage, which can enable enumeration or replay. When combined with missing rate limiting or insufficient input validation, attackers can probe for valid keys using automated scripts. Since API keys are often long-lived credentials, exposure can lead to persistent unauthorized access. This scenario aligns with BOLA/IDOR-type behaviors when key identifiers are predictable or weakly scoped, and it can be surfaced during a black-box scan in 5–15 seconds, producing a finding with severity and remediation guidance in the report.
middleBrick detects these issues by testing unauthenticated attack surfaces and, for Pro plans, can continuously monitor APIs to surface regressions. The scanner’s 12 security checks, including Authentication and BOLA/IDOR, run in parallel and can map findings to frameworks such as OWASP API Top 10 and SOC2. For LLM-related endpoints, the tool also applies LLM/AI Security checks to detect system prompt leakage or unauthorized usage patterns.
Api Keys-Specific Remediation in Fastapi — concrete code fixes
Secure API key handling in FastAPI requires explicit validation on every request, scoped usage, and avoiding accidental exposure. Below are concrete, working examples that demonstrate a robust approach.
Secure API key via header with dependency injection
from fastapi import FastAPI, Depends, Header, HTTPException, status
app = FastAPI()
VALID_API_KEYS = {"s3cr3t-k3y-01", "s3cr3t-k3y-02"} # in practice, store in a secure vault
def get_api_key(x_api_key: str = Header(None)):
if not x_api_key or x_api_key not in VALID_API_KEYS:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Invalid or missing API key",
headers={"WWW-Authenticate": "ApiKey"},
)
return x_api_key
@app.get("/secure/data")
def read_secure_data(api_key: str = Depends(get_api_key)):
return {"message": "authorized", "api_key_present": bool(api_key)}
Secure API key via query parameter with validation and constant-time comparison
import secrets
from fastapi import FastAPI, Depends, Query, HTTPException, status
app = FastAPI()
VALID_API_KEYS = {"s3cr3t-k3y-01", "s3cr3t-k3y-02"}
def get_api_key_from_query(api_key: str = Query(None)):
if not api_key or not secrets.compare_digest(api_key, "s3cr3t-k3y-01"):
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Invalid or missing API key",
headers={"WWW-Authenticate": "ApiKey"},
)
return api_key
@app.get("/secure/query")
def read_secure_query(api_key: str = Depends(get_api_key_from_query)):
return {"message": "authorized", "api_key_present": bool(api_key)}
Global dependency to enforce key on selected routes only
Use a global dependency if you want key enforcement across many routes but still allow exceptions for public endpoints:
from fastapi import FastAPI, Depends
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
app = FastAPI()
security_scheme = HTTPBearer()
def enforce_key(credentials: HTTPAuthorizationCredentials = Depends(security_scheme)):
# Replace with secure key validation logic
if credentials.credentials not in {"s3cr3t-k3y-01"}:
raise HTTPException(status_code=401, detail="Invalid key")
return credentials.credentials
@app.get("/public")
def public_endpoint():
return {"public": True}
@app.get("/private")
def private_endpoint(api_key: str = Depends(enforce_key)):
return {"private": True, "api_key": api_key}
Operational practices
- Never log raw API keys; mask or omit them in structured logs.
- Store keys in environment variables or a secrets manager; avoid hardcoding in source.
- Scope keys to specific roles or resources and rotate them periodically.
- Apply rate limiting to mitigate brute-force enumeration of valid keys.
- Ensure error messages do not reveal whether a key is malformed or simply missing.
These practices reduce the risk of authentication bypass and help align with OWASP API Top 10 controls. For ongoing assurance, teams on the Pro plan can enable continuous monitoring and CI/CD integration to fail builds if risk thresholds are exceeded.
Related CWEs: authentication
| CWE ID | Name | Severity |
|---|---|---|
| CWE-287 | Improper Authentication | CRITICAL |
| CWE-306 | Missing Authentication for Critical Function | CRITICAL |
| CWE-307 | Brute Force | HIGH |
| CWE-308 | Single-Factor Authentication | MEDIUM |
| CWE-309 | Use of Password System for Primary Authentication | MEDIUM |
| CWE-347 | Improper Verification of Cryptographic Signature | HIGH |
| CWE-384 | Session Fixation | HIGH |
| CWE-521 | Weak Password Requirements | MEDIUM |
| CWE-613 | Insufficient Session Expiration | MEDIUM |
| CWE-640 | Weak Password Recovery | HIGH |