HIGH type confusionfastapiapi keys

Type Confusion in Fastapi with Api Keys

Type Confusion in Fastapi with Api Keys — how this specific combination creates or exposes the vulnerability

Type confusion in FastAPI when using API keys typically occurs when the framework or developer code treats the key’s data type inconsistently, such as accepting both a string and a number where only a string is valid. This mismatch can bypass intended validation checks and allow an attacker to substitute a numeric or structured value for a string key, potentially reaching endpoints they should not access.

FastAPI relies on Pydantic models and parameter declarations to validate incoming requests. When an API key is declared as a string in a header or query parameter but the application logic or schema also permits numeric types, FastAPI may coerce or silently convert the value. This coercion can lead to a type confusion scenario where an integer like 12345 is accepted where a string key such as abc-123 is expected. Because the key no longer matches the format used for authorization logic, it may map to a different internal representation or permission set.

Consider an endpoint that expects an API key in the header for authorization, but the validation layer does not enforce strict string typing. An attacker could send 12345 instead of a formatted key. If downstream code compares the received value against a list of valid keys stored as strings, the type mismatch may cause the check to behave unpredictably. In some cases, this can unintentionally grant access or leak information about which keys are valid through timing differences or error messages.

OpenAPI specifications generated by FastAPI often define API key parameters as strings with a in: header or in: query location. However, if the spec is not strictly validated at runtime or if the developer uses looser types in path operations, the contract between documentation and implementation can diverge. middleBrick scans such endpoints during a black-box assessment and flags inconsistencies between the declared type in the spec and the actual accepted input, highlighting where type confusion could be exploited.

Another angle involves query parameters that should be strings but are interpreted as integers by the framework due to automatic type conversion. For example, a parameter like ?key=123 may be read as an integer if the route function declares the argument as int. If the authorization logic later compares this integer to a set of string-based keys, the comparison may fail in ways that expose which keys are valid or bypass checks entirely. This pattern is relevant for unauthenticated attack surface testing, which middleBrick performs as part of its API security checks.

Insecure deserialization patterns or dynamic endpoint generation can compound type confusion risks. If FastAPI routes are constructed based on user input without strict type enforcement, an attacker may craft requests that traverse unexpected code paths. The scanner tests such scenarios by probing endpoints with varied input types and analyzing how the application responds, surfacing misconfigurations that could lead to privilege escalation or unauthorized access.

Api Keys-Specific Remediation in Fastapi — concrete code fixes

To prevent type confusion with API keys in FastAPI, enforce strict typing and explicit validation at the boundary of your application. Define API key parameters as strings in both route declarations and Pydantic models, and avoid implicit type conversions. The following examples demonstrate secure patterns using header-based and query-based API keys.

Header-based API key with strict string type

from fastapi import FastAPI, Header, HTTPException

app = FastAPI()

VALID_KEYS = {"abc-123", "def-456"}

@app.get("/secure")
async def secure_endpoint(x_api_key: str = Header(...)):
    if x_api_key not in VALID_KEYS:
        raise HTTPException(status_code=401, detail="Invalid API key")
    return {"status": "ok"}

Query parameter API key with strict string type

from fastapi import FastAPI, Query, HTTPException

app = FastAPI()

VALID_KEYS = {"abc-123", "def-456"}

@app.get("/search")
async def search(
    api_key: str = Query(..., description="API key for authentication")
):
    if api_key not in VALID_KEYS:
        raise HTTPException(status_code=401, detail="Invalid API key")
    return {"results": []}

Pydantic model for structured API key validation

from fastapi import FastAPI, Depends
from pydantic import BaseModel, validator
from typing import ClassVar

app = FastAPI()

class ApiKeyPayload(BaseModel):
    key: str
    key_type: str = "public"

    @validator("key")
    def validate_key_format(cls, v):
        if not v.startswith("ak_"):
            raise ValueError("key must start with 'ak_'")
        return v

VALID_KEYS: ClassVar[set[str]] = {"ak_abc123", "ak_def456"}

@app.post("/auth")
async def authenticate(payload: ApiKeyPayload):
    if payload.key not in VALID_KEYS:
        raise HTTPException(status_code=401, detail="Unauthorized")
    return {"token": "example"}

Middleware enforcement to reject non-string keys

from fastapi import FastAPI, Request
from fastapi.responses import JSONResponse

app = FastAPI()

@app.middleware("http")
async def enforce_string_api_key(request: Request, call_next):
    api_key = request.headers.get("x-api-key")
    if api_key is not None and not isinstance(api_key, str):
        return JSONResponse(
            status_code=400,
            content={"detail": "API key must be a string"}
        )
    response = call_next(request)
    return response

Using dependencies with explicit type checks

from fastapi import Depends, HTTPException, status
from typing import Annotated

def get_api_key(api_key: str = Header(...)) -> str:
    if not isinstance(api_key, str):
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="API key must be a string"
        )
    return api_key

ApiKeyDep = Annotated[str, Depends(get_api_key)]

@app.get("/items")
async def list_items(api_key: ApiKeyDep):
    return {"data": "secure"}

These patterns ensure that API keys are consistently treated as strings, preventing type confusion. Combine this with automated security scans, such as those provided by middleBrick, to detect inconsistencies between your OpenAPI spec and runtime behavior. The CLI tool can be integrated into development workflows to validate configurations and surface risky parameter declarations before deployment.

Related CWEs: inputValidation

CWE IDNameSeverity
CWE-20Improper Input Validation HIGH
CWE-22Path Traversal HIGH
CWE-74Injection CRITICAL
CWE-77Command Injection CRITICAL
CWE-78OS Command Injection CRITICAL
CWE-79Cross-site Scripting (XSS) HIGH
CWE-89SQL Injection CRITICAL
CWE-90LDAP Injection HIGH
CWE-91XML Injection HIGH
CWE-94Code Injection CRITICAL

Frequently Asked Questions

Can type confusion in FastAPI with API keys lead to privilege escalation?
Yes. If numeric or malformed keys are accepted where strings are expected, an attacker may bypass authorization checks and access elevated endpoints, potentially leading to privilege escalation.
How can I verify that my FastAPI API key handling does not suffer from type confusion?
Use strict typing for header and query parameters, validate key format with Pydantic validators, and test endpoints with varied input types. Automated scans with tools like middleBrick can detect spec-to-runtime inconsistencies.