Insufficient Logging in Fastapi with Api Keys
Insufficient Logging in Fastapi with Api Keys — how this combination creates or exposes the vulnerability
Insufficient logging in a FastAPI application that uses API keys creates a gap in visibility that can enable or hide abuse. When API keys are accepted via headers or query parameters, each request should be recorded in a structured way so that anomalous patterns—such as repeated invalid keys, sudden spikes in calls from a single key, or usage from unexpected geographies—can be detected. Without these logs, defenders lack the data needed to investigate incidents, tune rate-limiting, or demonstrate due diligence during audits.
In FastAPI, a common pattern is to read the API key from a header and perform a simple comparison, but omitting explicit logging at authentication boundaries means successful and failed attempts may go unrecorded. For example, if a request fails key validation and the developer does not log the event (including the key identifier, request path, timestamp, and client IP), an attacker can probe keys with little risk of detection. Similarly, logging the entire header without redaction can expose secrets; best practice is to log a fingerprint or token ID rather than the raw key.
When OpenAPI/Swagger specs are analyzed alongside runtime behavior, tools like middleBrick can highlight whether authentication events are consistently logged and whether logs retain enough context (key ID, endpoint, status) for post-incident analysis. The scan checks align with the OWASP API Top 10 category for Security Logging and Monitoring Failures, mapping to broader compliance frameworks such as SOC 2 and PCI-DSS where audit trails are required. middleBrick also tests for excessive data exposure in responses, which can complement logging reviews by ensuring that sensitive information is not inadvertently surfaced in API output.
Another dimension involves correlation across services. A FastAPI service might authenticate with an API key but rely on downstream systems for authorization; if those downstream calls are not logged with a traceable request ID, the overall transaction chain becomes opaque. Instrumentation with structured logs and correlation IDs improves observability and supports root cause analysis. middleBrick’s inventory management and property authorization checks can surface whether resource-level logging is consistent across endpoints, helping teams understand whether authorization decisions are recorded with sufficient granularity.
Finally, LLM endpoints integrated behind FastAPI routes introduce additional logging considerations. If model prompts or responses contain sensitive data, logging must avoid capturing PII or secrets while still preserving enough detail to trace misuse. middleBrick’s LLM/AI security checks include system prompt leakage detection and output scanning, which highlight risks when AI endpoints are combined with weak logging. By combining runtime scans with robust log management practices, teams can close visibility gaps that would otherwise allow abuse to persist undetected.
Api Keys-Specific Remediation in Fastapi — concrete code fixes
To address insufficient logging when using API keys in FastAPI, implement structured logging at authentication points and ensure sensitive data is not stored in logs. Below is a complete, syntactically correct example that demonstrates how to validate API keys, attach key metadata to the request state, and emit structured logs without exposing secrets.
from fastapi import FastAPI, Depends, Header, HTTPException, Request, status
import logging
import hashlib
import json
# Configure structured logging (e.g., JSON) for easier ingestion by SIEM
logging.basicConfig(
level=logging.INFO,
format='%(message)s',
handlers=[logging.StreamHandler()]
)
logger = logging.getLogger(__name__)
app = FastAPI()
# Example key store; in production use a secure vault or database
VALID_KEYS = {
"abc123": {"owner": "service-a", "scopes": ["read", "write"]},
"def456": {"owner": "service-b", "scopes": ["read"]},
}
def fingerprint_key(key: str) -> str:
"""Return a non-reversible fingerprint for logging."""
return hashlib.sha256(key.encode()).hexdigest()[:16]
def get_api_key(x_api_key: str = Header(None)):
if not x_api_key:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Missing API key",
)
return x_api_key
@app.middleware("http")
async def log_request_state(request: Request, call_next):
"""Attach key metadata to request state for downstream use and log attempts."""
api_key = request.headers.get("X-API-Key")
key_fingerprint = fingerprint_key(api_key) if api_key else None
# Store minimal metadata on the request state for handlers
request.state.key_fingerprint = key_fingerprint
request.state.key_owner = None
request.state.key_scopes = []
response = await call_next(request)
# Log structured event with fingerprint, path, method, and outcome
log_data = {
"event": "api_request",
"timestamp": request.scope.get("time", "").isoformat() if hasattr(request.scope.get("time"), "isoformat") else str(request.scope.get("time")),
"method": request.method,
"path": request.url.path,
"key_fingerprint": key_fingerprint,
"status_code": response.status_code,
"client_ip": request.client.host if request.client else None,
}
if response.status_code == 401:
logger.warning(json.dumps(log_data))
else:
logger.info(json.dumps(log_data))
return response
@app.get("/items")
async def list_items(api_key: str = Depends(get_api_key)):
key_info = VALID_KEYS.get(api_key)
if not key_info:
logger.warning(json.dumps({
"event": "auth_failure",
"key_fingerprint": fingerprint_key(api_key),
"path": "/items",
"reason": "invalid_key"
}))
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Invalid API key")
# Attach owner and scopes for downstream authorization
from fastapi import Request
request = Request(request.scope, request.receive)
# In real usage, retrieve request from context or pass via dependency
return {"data": ["item1", "item2"], "owner": key_info["owner"]}
This pattern ensures that each authentication attempt is recorded with a fingerprint rather than the raw key, protecting secrets while enabling monitoring. It also demonstrates how to propagate ownership and scope information into request state for use in authorization logic.
For production, integrate with a secrets manager for VALID_KEYS, add rate-limiting to reduce brute-force risk, and forward structured logs to a centralized system. middleBrick’s CLI can be used in CI/CD to verify that logging and authentication patterns remain consistent after changes, while the GitHub Action can enforce minimum security scores before deployment.