HIGH format stringfastapiapi keys

Format String in Fastapi with Api Keys

Format String in Fastapi with Api Keys — how this combination creates or exposes the vulnerability

A Format String vulnerability occurs when user-controlled input is passed directly into a formatting function such as str.format, , or logging string interpolation without proper sanitization. In FastAPI, this risk is amplified when API keys are handled carelessly—for example, logging an incoming key with a format placeholder or echoing it in a response message that includes unchecked user input.

Consider a FastAPI endpoint that receives an API key in a header and logs it using an f-string combined with external data:

from fastapi import FastAPI, Header, HTTPException
import logging

logging.basicConfig(level=logging.INFO)
app = FastAPI()

@app.get("/items/")
async def read_items(x_api_key: str = Header(...)):
    user_supplied = "unknown"
    # UNSAFE: user_supplied is used inside an f-string with the API key
    logging.info(f"Received API key {x_api_key} for user {user_supplied}")
    return {"key": x_api_key, "user": user_supplied}

If an attacker sends a crafted header such as X-Api-Key: %s%s%s%s, the log output can expand to consume memory or leak surrounding memory contents, potentially exposing other secrets or causing denial of service. More broadly, format strings can reveal whether an API key is being processed, its length, and structure through log timing or error messages, aiding reconnaissance for further attacks.

The same risk appears when API keys are reflected in HTTP responses or error messages using insecure formatting, for instance:

from fastapi import FastAPI, Query

app = FastAPI()

@app.get("/echo/")
async def echo(key: str = Query(...)):
    # UNSAFE: key is interpolated directly into a user-facing string
    return {"message": "Your key is {}".format(key)}

Although this example may seem benign, if the key contains format specifiers (e.g., {user_id}), Python’s str.format can interpret them, leading to unintended substitutions or information disclosure. In the context of API security checks run by middleBrick, such patterns are flagged because they expose API keys through logging or output formatting, violating data exposure controls.

In broader assessments, format string issues intersect with authentication and data exposure checks. middleBrick’s scans test unauthenticated endpoints and can surface these patterns when OpenAPI specs or runtime behavior reveal insecure string handling of credentials. Remediation focuses on avoiding direct interpolation of secrets and never reflecting raw keys in responses or logs.

Api Keys-Specific Remediation in Fastapi — concrete code fixes

Secure handling of API keys in FastAPI requires keeping keys out of logs, avoiding dynamic formatting with user input, and ensuring keys are treated as opaque strings. Below are concrete, safe patterns.

1. Use structured logging without interpolating secrets

Log metadata separately from the API key value. Never include the key inside a formatted string that also includes user-controlled fields.

import logging
from fastapi import FastAPI, Header

logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

app = FastAPI()

@app.get("/items/")
async def read_items(x_api_key: str = Header(...)):
    # SAFE: log a hash or a fixed message, not the key itself
    logger.info("API key received", extra={"key_hash": hash(x_api_key)})
    return {"status": "ok"}

2. Avoid reflection of raw keys in responses

Do not return the API key in JSON or error messages. If you must acknowledge receipt, use a constant, non-sensitive response.

from fastapi import FastAPI, Header

app = FastAPI()

@app.get("/validate/")
async def validate_key(x_api_key: str = Header(...)):
    # SAFE: do not echo the key
    return {"valid": True}

3. Use environment variables and secure configuration

Load API keys from environment variables and access them via settings, ensuring they are never constructed from user input.

import os
from fastapi import FastAPI

app = FastAPI()

API_KEY = os.getenv("SERVICE_API_KEY")

@app.get("/check/")
async def check_key(x_api_key: str = Header(...)):
    if x_api_key != API_KEY:
        raise HTTPException(status_code=403, detail="Invalid key")
    return {"result": "authorized"}

4. Disable unnecessary debug output in production

Ensure logging levels and formats do not inadvertently print raw headers. Configure loggers explicitly to exclude sensitive fields.

import logging
from fastapi import FastAPI, Header

# Configure a filter that redacts sensitive header names in logs
class RedactFilter(logging.Filter):
    def filter(self, record):
        if "x_api_key" in record.getMessage():
            return False
        return True

logger = logging.getLogger(__name__)
logger.addFilter(RedactFilter())

app = FastAPI()

@app.get("/items/")
async def read_items(x_api_key: str = Header(...)):
    logger.info("Request processed")
    return {"status": "ok"}

By following these practices, you reduce the risk of format string–related information leakage involving API keys. middleBrick’s checks for Authentication and Data Exposure will highlight insecure logging or reflection patterns, guiding you toward safer credential handling in FastAPI services.

Frequently Asked Questions

Can a format string issue lead to API key exposure even if the key is stored server-side?
Yes. If server-side code logs or echoes an API key using user-controlled format strings, the key can appear in logs or error output, exposing it to unauthorized parties.
Does middleBrick test for format string vulnerabilities during scans?
Yes. middleBrick’s Data Exposure and Input Validation checks identify patterns where secrets may be improperly formatted or reflected, including log entries and API responses.