HIGH double freefastapi

Double Free in Fastapi

How Double Free Manifests in Fastapi

In Fastapi, a double-free pattern can arise when request lifecycle dependencies are released or cleaned up more than once, typically because the application or an underlying library processes a cleanup step after an early exit or exception. Common scenarios include manual resource handling in dependency callbacks, misuse of context managers, or incorrect interaction between middleware and endpoint logic.

Consider a dependency that opens a network or file handle and registers a cleanup callback. If the endpoint raises an exception before the dependency completes normally, Fastapi may still attempt to run cleanup again when the request context tears down, leading to a double-free class of vulnerability. For example:

from fastapi import Depends, FastAPI, HTTPException
from pydantic import BaseModel
import some_external_library

app = FastAPI()

class Item(BaseModel):
    name: str

def get_resource():
    handle = some_external_library.open()
    def cleanup():
        some_external_library.close(handle)
    request_state = some_external_library.allocate_state()
    request_state.callback = cleanup
    return handle

@app.post("/items/")
async def create_item(item: Item, handle: str = Depends(get_resource)):
    if not item.name:
        raise HTTPException(status_code=400, detail="name required")
    some_external_library.process(handle, item.name)
    return {"status": "ok"}

If some_external_library.process raises an exception, Fastapi’s exception handlers may still invoke the dependency’s cleanup, while the runtime or the library itself may also attempt to release the same resource, resulting in a double-free condition. This can corrupt internal bookkeeping, crash worker processes, or lead to undefined behavior in native extensions.

Another Fastapi-specific pattern involves nested dependencies where one dependency performs partial cleanup and another dependency or middleware tries to clean the same resource. For instance, using Depends with yield for setup/teardown alongside global middleware that also interacts with the same resource can create overlapping release points:

from fastapi import Depends, FastAPI
from contextlib import asynccontextmanager

app = FastAPI()

@asynccontextmanager
async def lifespan(app: FastAPI):
    resource = acquire()
    try:
        yield resource
    finally:
        release(resource)

async def get_db():
    db = acquire_db()
    try:
        yield db
    finally:
        release_db(db)

@app.post("/data/")
async def handle(db = Depends(get_db)):
    # If an exception occurs before yield, Fastapi may still run both
    # the dependency teardown and the lifespan cleanup for overlapping resources
    pass

Although Fastapi does not manage memory manually, these patterns can propagate to native extensions or external services where double-free vulnerabilities are exploitable. The risk is especially pronounced when C extensions or libraries used by Fastapi do not guard against repeated release calls.

Fastapi-Specific Detection

Detecting double-free risks in Fastapi involves correlating dependency lifecycles, exception paths, and resource management patterns. Static analysis can highlight missing guards around cleanup routines, but runtime scanning is essential to observe actual execution paths and teardown behavior under errors.

Using middleBrick, you can scan a Fastapi endpoint to surface security findings across categories including unsafe consumption and unsafe resource handling. The scanner exercises unauthenticated attack surfaces and maps findings to the endpoint’s OpenAPI spec, cross-referencing definitions with runtime behavior. For example, it flags dependencies that yield resources without strict exception guards and highlights endpoints where exceptions trigger multiple teardown attempts.

A practical detection flow with the CLI is straightforward:

middlebrick scan https://api.example.com/openapi.json

The output includes a per-category breakdown, prioritized findings, and remediation guidance. In the context of Fastapi, findings may point to dependencies using yield without ensuring idempotent cleanup or to endpoints where validation errors skip normal release paths. The scanner’s input validation and unsafe consumption checks are especially useful for identifying paths that lead to resource misuse.

Because middleBrick runs black-box scans without agents or credentials, it can be integrated into CI/CD to validate that changes to dependencies or error handling do not introduce or regress double-free conditions. The GitHub Action can enforce a minimum security score before allowing merges, while the MCP Server lets you trigger scans directly from AI coding assistants as you write dependency code.

Fastapi-Specific Remediation

Remediation focuses on making cleanup idempotent and ensuring a single release point per resource. Use Fastapi’s native dependency system carefully by avoiding manual double-release in both success and error paths. Implement guards such as flags or state checks inside cleanup routines, and prefer context managers that handle repeated calls safely.

Refactor yield-based dependencies to use explicit try/finally blocks and ensure that exceptions do not bypass teardown logic. Centralize resource management in a dedicated service that tracks released state:

from fastapi import Depends, FastAPI, HTTPException
from contextlib import asynccontextmanager

app = FastAPI()

class ResourceManager:
    def __init__(self):
        self._released = set()

    def acquire(self):
        # simplified
        return "handle"

    def release(self, handle):
        if handle in self._released:
            return  # idempotent guard
        # actual cleanup
        self._released.add(handle)

manager = ResourceManager()

def get_safe_resource():
    handle = manager.acquire()
    def cleanup():
        manager.release(handle)
    request_state = {"cleanup": cleanup}
    return handle

@app.post("/items/")
async def create_item(handle: str = Depends(get_safe_resource)):
    try:
        # process item
        pass
    except Exception:
        # trigger cleanup explicitly if needed
        manager.release(handle)
        raise

Alternatively, use Fastapi’s Depends with a context manager to guarantee that cleanup runs once, even when errors occur:

from contextlib import asynccontextmanager
from fastapi import Depends, FastAPI

app = FastAPI()

@asynccontextmanager
async def database_session():
    db = acquire_db()
    try:
        yield db
    finally:
        # ensure idempotent release in the db driver
        safe_release_db(db)

@app.get("/items/")
async def list_items(db = Depends(database_session)):
    return list(db.query("items"))

Validate that external libraries implement idempotent release functions and, where possible, wrap them with safe guards. Combine these practices with middleBrick’s continuous monitoring to detect regressions early, ensuring that dependency changes do not reintroduce double-free risks.

Frequently Asked Questions

Can middleBrick detect double-free risks in Fastapi without access to source code?
Yes. middleBrick performs black-box scans against the running API, testing unauthenticated endpoints and dependencies. It correlates dependency lifecycles and exception paths observed during runtime to surface double-free patterns, even without source code.
How does middleBrick map findings to compliance frameworks for Fastapi APIs?
middleBrick maps findings to OWASP API Top 10, PCI-DSS, SOC2, HIPAA, and GDPR by categorizing issues such as unsafe consumption and improper resource handling. The dashboard provides per-category breakdowns and prioritized remediation guidance aligned with these frameworks.