Zip Slip in Fastapi with Api Keys
Zip Slip in Fastapi with Api Keys — how this specific combination creates or exposes the vulnerability
Zip Slip is a path traversal vulnerability that occurs when an API constructs file paths by directly concatenating user-supplied input with a base directory. In Fastapi, endpoints that accept archive files (for example, a file upload or an archive URL) and then extract contents using the provided file name can become vulnerable if archive entries are not validated. When Api Keys are used for authentication, developers may assume that the identity represented by the key protects sensitive file system operations. However, authentication and authorization are distinct: Api Keys can confirm who is making the request, but they do not automatically enforce that the extracted content stays within intended boundaries. If the endpoint trusts the key and does not validate or sanitize archive entries, an attacker can supply a crafted archive containing paths like ../../../etc/passwd or files outside the extraction directory. During extraction, these paths can traverse outside the intended directory, leading to unauthorized file read or, in some conditions, write operations. middleBrick scans such unauthenticated attack surfaces and flags related findings under BFLA/Privilege Escalation and Input Validation checks, highlighting the risk even when Api Keys are present. This combination shows that authentication does not prevent path traversal; secure path handling is still required.
Api Keys-Specific Remediation in Fastapi — concrete code fixes
To remediate Zip Slip in Fastapi while using Api Keys, enforce strict path validation and avoid direct concatenation of user input into file system paths. Below are two focused code examples that demonstrate secure handling.
Example 1: Secure file extraction with Api Key authentication
Use a whitelist approach for allowed entry names and normalize paths to ensure they resolve inside a designated directory. This example uses Path.resolve() and Path.is_relative_to() (Python 3.9+) to confirm containment.
from fastapi import Fastapi, UploadFile, File, HTTPException, Depends, Header
from pathlib import Path
import zipfile
import tempfile
import os
app = Fastapi()
# Simulated Api Key validation dependency
def get_current_api_key(x_api_key: str = Header(...)):
valid_keys = {"trusted-key-123", "trusted-key-456"}
if x_api_key not in valid_keys:
raise HTTPException(status_code=401, detail="Invalid Api Key")
return x_api_key
@app.post("/upload-extract")
async def upload_extract(file: UploadFile = File(...), api_key: str = Depends(get_current_api_key)):
upload_dir = Path("/safe/upload/extract")
upload_dir.mkdir(parents=True, exist_ok=True)
if not file.filename.endswith(".zip"):
raise HTTPException(status_code=400, detail="Only ZIP files are allowed")
with tempfile.NamedTemporaryFile(suffix=".zip", delete=False) as tmp:
tmp.write(file.file.read())
tmp_path = Path(tmp.name)
try:
with zipfile.ZipFile(tmp_path, "r") as zf:
for member in zf.infolist():
member_path = Path(member.filename).name # Use only the final name, discarding directory components
target = upload_dir / member_path
# Ensure the resolved target stays inside the allowed directory
if not target.resolve().is_relative_to(upload_dir.resolve()):
raise HTTPException(status_code=400, detail="Invalid path in archive")
zf.extract(member, path=upload_dir)
finally:
tmp_path.unlink(missing_ok=True)
return {"message": "Extraction completed", "destination": str(upload_dir)}
Example 2: Parameterized endpoint with strict path sanitization
When endpoints accept a target filename, validate against a pattern and use Path operations to avoid directory traversal. This example demonstrates how to combine Api Key checks with safe path construction.
from fastapi import Fastapi, Query, HTTPException, Depends, Header
from pathlib import Path
def get_current_api_key(x_api_key: str = Header(...)):
valid_keys = {"trusted-key-123", "trusted-key-456"}
if x_api_key not in valid_keys:
raise HTTPException(status_code=401, detail="Invalid Api Key")
return x_api_key
app = Fastapi()
@app.get("/files/{safe_name}")
async def read_file(safe_name: str = Path(..., description="A sanitized filename without path components"), api_key: str = Depends(get_current_api_key)):
base = Path("/data/files")
# Reject path-like input
if ".." in safe_name or "/" in safe_name or "\\" in safe_name:
raise HTTPException(status_code=400, detail="Invalid filename")
target = (base / safe_name).resolve()
if not target.is_relative_to(base.resolve()):
raise HTTPException(status_code=403, detail="Access denied")
if not target.exists() or not target.is_file():
raise HTTPException(status_code=404, detail="File not found")
return {"file": target.read_text()}
These patterns emphasize that Api Keys provide identity but do not replace secure path handling. By normalizing and constraining paths, and by validating archive entries, you reduce the risk of Zip Slip even when keys are present. middleBrick can identify related issues such as BFLA/Privilege Escalation and Input Validation in scans, helping you verify that such protections are correctly applied.