HIGH zip slipfastapi

Zip Slip in Fastapi

How Zip Slip Manifests in Fastapi

Zip Slip is a directory traversal vulnerability that occurs when an application extracts files from an archive without properly validating the file paths. In Fastapi applications, this typically manifests when handling file uploads or processing archives sent through API endpoints.

The vulnerability exploits path traversal sequences like ../../ in filenames within zip archives. When an attacker crafts a malicious zip file with paths like ../../etc/passwd or ../../../windows/system32/calc.exe, the extraction process can write files outside the intended directory, potentially overwriting system files or accessing sensitive areas of the filesystem.

In Fastapi, Zip Slip commonly appears in these scenarios:

  • File upload endpoints that accept zip archives for processing
  • API endpoints that extract template files or assets
  • Background tasks that process uploaded archives
  • Endpoints that handle backup/restore functionality

Here's a vulnerable Fastapi endpoint that demonstrates the issue:

from fastapi import FastAPI, File, UploadFile
from fastapi.responses import JSONResponse
import zipfile
import os

app = FastAPI()

@app.post("/upload-archive/")
async def upload_archive(file: UploadFile = File(...)):
    # Vulnerable: no path validation
    extract_path = "/var/www/uploads"
    
    with zipfile.ZipFile(file.file, 'r') as zip_ref:
        zip_ref.extractall(extract_path)
    
    return JSONResponse(content={"message": "Archive processed"})

An attacker could upload a zip containing:

../../../../../etc/passwd
../../../../../etc/shadow
../../../windows/system32/calc.exe

This would extract these files outside the intended directory, potentially overwriting critical system files or exposing sensitive data.

Another Fastapi-specific manifestation occurs when using background tasks for archive processing:

from fastapi import FastAPI, File, UploadFile
from fastapi.responses import JSONResponse
import zipfile
import os
from concurrent.futures import ThreadPoolExecutor

app = FastAPI()
executor = ThreadPoolExecutor()

@app.post("/upload-archive-bg/")
async def upload_archive_bg(file: UploadFile = File(...)):
    # Vulnerable: background task still extracts without validation
    await asyncio.get_event_loop().run_in_executor(
        executor, process_archive, file.file
    )
    return JSONResponse(content={"message": "Archive queued for processing"})

def process_archive(file_stream):
    extract_path = "/var/www/uploads"
    with zipfile.ZipFile(file_stream, 'r') as zip_ref:
        zip_ref.extractall(extract_path)

The background processing doesn't change the vulnerability—the path traversal issue remains.

Fastapi-Specific Detection

Detecting Zip Slip in Fastapi applications requires both static analysis of your code and dynamic scanning of your API endpoints. For Fastapi specifically, focus on these detection methods:

Static Code Analysis

Review your Fastapi endpoints that handle file uploads or archive processing. Look for these red flags:

# Dangerous patterns to search for:
zipfile.ZipFile(...).extractall(path)  # No path validation
zipfile.ZipFile(...).extract(member, path)  # No path validation
# Any file operation with user-controlled paths
open(user_provided_path, 'w')

Dynamic Scanning with middleBrick

middleBrick's black-box scanning approach is particularly effective for detecting Zip Slip in Fastapi applications because it tests the actual runtime behavior without needing source code access.

To scan your Fastapi API:

# Install middleBrick CLI
npm install -g middlebrick

# Scan your Fastapi endpoint
middlebrick scan http://localhost:8000/upload-archive/

middleBrick tests for Zip Slip by attempting to extract specially crafted zip files with path traversal sequences. The scanner creates archives with filenames containing ../../ patterns and verifies whether the application allows extraction outside the intended directory.

Manual Testing Methodology

If you want to manually test your Fastapi application for Zip Slip:

  1. Create a test zip file with traversal paths:
    echo "test" > evil.txt
    mkdir -p test_traversal/evil_path
    zip -r traversal_test.zip test_traversal/evil_path/../../evil.txt
    
  2. Attempt to upload to your Fastapi endpoint
  3. Check if the file appears outside the intended directory
  4. Verify if the application handled the traversal safely

middleBrick's Zip Slip Detection Features

middleBrick specifically tests for:

  • Path traversal in zip archive extraction
  • Directory traversal in tar archives (tar slip)
  • Path validation bypass attempts
  • Symbolic link exploitation within archives

The scanner provides detailed findings including:

  • Exact path traversal sequences that succeeded
  • Files that were extracted outside intended directories
  • Severity assessment with CVSS scoring
  • Remediation guidance specific to Fastapi applications

For Fastapi applications, middleBrick's continuous monitoring feature (Pro plan) can automatically re-scan your API endpoints on a schedule, alerting you if new Zip Slip vulnerabilities are introduced in updates.

Fastapi-Specific Remediation

Remediating Zip Slip in Fastapi applications requires implementing proper path validation before extracting archives. Here are Fastapi-specific solutions:

Safe Archive Extraction with Path Validation

The most robust approach is to validate all paths before extraction:

from fastapi import FastAPI, File, UploadFile
from fastapi.responses import JSONResponse
import zipfile
import os
import pathlib

app = FastAPI()

SAFE_EXTRACT_DIR = pathlib.Path("/var/www/uploads")

def is_safe_path(base_path, target_path, follow_symlinks=True):
    # Resolve both paths and check if target is within base
    base_path = pathlib.Path(base_path).resolve()
    target_path = pathlib.Path(target_path).resolve()
    
    try:
        if follow_symlinks:
            # Check if base path is same as target path or a parent
            return str(base_path) == str(target_path) or str(base_path) in str(target_path.parent)
        else:
            # Check if base path is same as target path or a parent (without resolving symlinks)
            return str(base_path) == str(target_path) or str(base_path) in str(target_path.parent)
    except (OSError, RuntimeError):
        # If there's an error accessing the paths, reject
        return False

@app.post("/upload-archive-safe/")
async def upload_archive_safe(file: UploadFile = File(...)):
    extract_path = SAFE_EXTRACT_DIR
    
    with zipfile.ZipFile(file.file, 'r') as zip_ref:
        for member in zip_ref.namelist():
            # Construct the full target path
            target_path = extract_path / member
            
            # Validate the path is safe
            if not is_safe_path(extract_path, target_path):
                return JSONResponse(
                    status_code=400,
                    content={"error": f"Path traversal attempt detected: {member}"}
                )
        
        # If all paths are safe, extract
        zip_ref.extractall(extract_path)
    
    return JSONResponse(content={"message": "Archive processed securely"})

Using a Dedicated Library for Safe Extraction

For production Fastapi applications, consider using a library designed for safe archive extraction:

from fastapi import FastAPI, File, UploadFile
from fastapi.responses import JSONResponse
import patoolib
import os

app = FastAPI()

@app.post("/upload-archive-patool/")
async def upload_archive_patool(file: UploadFile = File(...)):
    extract_path = "/var/www/uploads"
    
    try:
        # patoolib handles path traversal automatically
        patoolib.extract_archive(file=file.file, outdir=extract_path, interactive=False)
        return JSONResponse(content={"message": "Archive processed securely"})
    except patoolib.util.PatoolError as e:
        return JSONResponse(
            status_code=400,
            content={"error": f"Archive extraction failed: {str(e)}"}
        )

Fastapi Middleware for Archive Protection

Implement a Fastapi dependency to automatically validate archive uploads:

from fastapi import Depends, HTTPException, UploadFile
from fastapi.responses import JSONResponse
import zipfile
import pathlib

async def validate_archive(file: UploadFile = File(...)):
    extract_path = pathlib.Path("/var/www/uploads")
    
    with zipfile.ZipFile(file.file, 'r') as zip_ref:
        for member in zip_ref.namelist():
            target_path = extract_path / member
            if not is_safe_path(extract_path, target_path):
                raise HTTPException(
                    status_code=400,
                    detail=f"Path traversal attempt detected: {member}"
                )
    
    # Reset file pointer for downstream processing
    file.file.seek(0)
    return file

@app.post("/upload-archive-with-dep/")
async def upload_archive_with_dep(
    file: UploadFile = Depends(validate_archive)
):
    # File is already validated, safe to process
    extract_path = "/var/www/uploads"
    with zipfile.ZipFile(file.file, 'r') as zip_ref:
        zip_ref.extractall(extract_path)
    
    return JSONResponse(content={"message": "Archive processed securely"})

Testing Your Remediation

After implementing fixes, use middleBrick to verify your remediation:

# Test your fixed endpoint
middlebrick scan http://localhost:8000/upload-archive-safe/

middleBrick will attempt to exploit Zip Slip and confirm whether your validation logic successfully blocks path traversal attempts. The scanner provides specific feedback on whether your remediation is effective.

For Fastapi applications in production, consider implementing the Pro plan's continuous monitoring to automatically re-scan your API endpoints whenever code changes are deployed, ensuring new Zip Slip vulnerabilities aren't introduced in future updates.

Frequently Asked Questions

How can I test if my Fastapi application is vulnerable to Zip Slip?
Create a zip file with paths containing ../../ sequences and attempt to upload it to your Fastapi endpoint. If files are extracted outside the intended directory, you're vulnerable. Alternatively, use middleBrick's black-box scanning which automatically tests for Zip Slip by attempting path traversal during archive extraction.
Does Fastapi have built-in protection against Zip Slip?
No, Fastapi does not have built-in protection against Zip Slip. The framework provides the foundation for building APIs but does not include archive extraction security features. You must implement path validation manually or use a dedicated library like patoolib that handles path traversal safely.