Container Escape in Fastapi with Basic Auth
Container Escape in Fastapi with Basic Auth — how this specific combination creates or exposes the vulnerability
A container escape in a FastAPI service that uses HTTP Basic Authentication can occur when authentication decisions are handled at the application layer while the runtime environment exposes container-level primitives or misconfigured endpoints. FastAPI applications often rely on Basic Auth for simplicity, parsing the Authorization header and mapping credentials to permissions. If the app runs inside a container with access to the Docker socket (/var/run/docker.sock) or exposes administrative endpoints (e.g., interactive debug tools or open Prometheus endpoints), an authenticated or unauthenticated attacker may leverage insecure default configurations or overlooked routes to execute commands on the host.
Consider a FastAPI app using Basic Auth for route protection but also embedding an interactive OpenAPI UI at /docs that is inadvertently exposed without additional host checks. If the container runs with elevated privileges or mounts sensitive host paths, an attacker authenticated with Basic Auth (or exploiting an unauthenticated SSRF or unsafe consumption check) could traverse paths accessible to the container process and interact with the socket. This could lead to spawning containers on the host, reading files outside the container namespace, or injecting malicious workloads, effectively breaking container isolation.
Another scenario involves FastAPI’s dependency injection system combined with misconfigured middleware or CORS settings. An endpoint that accepts user input to construct system commands (e.g., via subprocess) and is protected only by Basic Auth can be abused if the authentication header is parsed incorrectly or if default development settings remain in production. For example, if the app uses shell=True with user-controlled arguments, an attacker who obtains valid credentials or exploits an input validation weakness can inject shell metacharacters to escape the container’s filesystem boundaries.
In the context of middleBrick’s 12 checks, a scan targeting a FastAPI endpoint with Basic Auth would surface risks under several categories: Input Validation (malformed headers or path traversal), Unsafe Consumption (command injection via headers or query parameters), BFLA/Privilege Escalation (overprivileged container runtime), and Data Exposure (sensitive paths mounted into the container). The scanner correlates runtime behavior with the OpenAPI spec, identifying routes that accept Basic Auth and checking whether they interact with host-level resources. Without active runtime isolation controls outside the scan’s scope, the findings highlight where defense-in-depth measures—such as non-root execution, read-only filesystems, and restricted socket access—are missing.
Basic Auth-Specific Remediation in Fastapi — concrete code fixes
To reduce container escape risk when using HTTP Basic Authentication in FastAPI, enforce strict input handling, avoid shell interaction, and minimize container privileges. Below are concrete, secure code examples you can adopt.
Secure Basic Auth implementation in FastAPI
Use dependency injection with explicit security schemes and constant-time comparison to avoid header parsing exploits. Never forward raw headers to subprocesses or shell commands.
from fastapi import FastAPI, Depends, HTTPException, Security, status
from fastapi.security import HTTPBasic, HTTPBasicCredentials
import secrets
import hashlib
app = FastAPI()
security = HTTPBasic()
# In production, use a secure secret store or environment variables
EXPECTED_USER = "apiuser"
EXPECTED_PASS_HASH = hashlib.sha256(b"StrongPass!2025").hexdigest()
def verify_basic_auth(credentials: HTTPBasicCredentials = Security(security)):
correct_user = secrets.compare_digest(credentials.username, EXPECTED_USER)
provided_pass_hash = hashlib.sha256(credentials.password.encode("utf-8")).hexdigest()
correct_pass = secrets.compare_digest(provided_pass_hash, EXPECTED_PASS_HASH)
if not (correct_user and correct_pass):
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Invalid authentication credentials",
headers={"WWW-Authenticate": "Basic"},
)
return credentials.username
@app.get("/secure-data")
def read_secure_data(username: str = Depends(verify_basic_auth)):
# Minimal container access: do not invoke shell commands with user input
return {"message": f"Authenticated as {username}", "data": "safe payload"}
In this example, secrets.compare_digest mitigates timing attacks on credentials. The password is verified against a pre-hashed value, avoiding plaintext storage. The endpoint does not invoke subprocesses or expose debug routes that could be leveraged for host interaction.
Harden the container runtime
Code changes must be complemented by container hardening: run as a non-root user, use read-only filesystems where possible, and avoid mounting the Docker socket. Define resource limits and drop unnecessary Linux capabilities. For FastAPI, ensure debug mode is disabled (app.debug = False) and that the OpenAPI UI is restricted behind network policies or additional authentication if exposed.
Avoid unsafe consumption patterns
Never use user-supplied header values in shell commands. If system operations are required, use language-level APIs with strict input validation. For instance, prefer pathlib.Path with absolute path validation over string concatenation, and avoid subprocess.run(..., shell=True). middleBrick’s checks for Unsafe Consumption and BFLA help surface these patterns during scans.