HIGH zip slipactixfirestore

Zip Slip in Actix with Firestore

Zip Slip in Actix with Firestore — how this specific combination creates or exposes the vulnerability

A Zip Slip vulnerability occurs when an application constructs file paths from user-supplied input without proper validation, enabling directory traversal that writes files outside the intended directory. In an Actix web service that integrates with Google Cloud Firestore, the risk has two dimensions: the web layer (Actix routes and extractors) and the data layer (Firestore operations). Although Firestore itself does not use a traditional filesystem, an Actix handler might first receive a user-controlled filename, use it to build a local temporary path (for upload, caching, or logging), and then write data into Firestore based on that same input. If the filename is not canonicalized and validated, an attacker can supply paths such as ../../../malicious.txt to traverse directories. Even when the final data is stored in Firestore, the insecure handling of the filename before it reaches Firestore can lead to unauthorized file writes on the host, exposure of temporary files, or confusion about the source of data that is later referenced in Firestore documents.

Specifically, if an Actix handler uses a path-building approach like concatenating a user-provided file_name to a base directory and then stores metadata or a generated key into Firestore, the lack of path traversal checks means the effective target location can escape the intended sandbox. An attacker may leverage this to overwrite configuration files, interfere with other services on the same host, or manipulate auxiliary systems that read the same filesystem. In a Firestore-centric design, the handler might still store sanitized document IDs or bucket keys, but if the filename is used locally before being sent to Firestore, the vulnerability exists at the boundary between the web framework and the filesystem, not inside Firestore itself. The Firestore-specific exposure arises when the compromised file influences what metadata or paths are later recorded in Firestore, potentially enabling further abuse such as confused deputy scenarios or unauthorized access to downstream services that consume the stored references.

To illustrate a vulnerable pattern in Actix with Firestore, consider an endpoint that accepts a filename and some data, writes the data locally, and then stores a reference in Firestore. Without proper validation, the filename can traverse directories:

use actix_web::{post, web, HttpResponse};
use google_cloud_firestore::client::Client;
use std::path::Path;
use std::fs;

#[post("/upload")]
async fn upload(
    form: web::Form,
    client: web::Data,
) -> HttpResponse {
    let base = "/tmp/uploads";
    // Vulnerable: user-controlled file_name used directly
    let file_path = Path::new(base).join(&form.file_name);
    if let Some(parent) = file_path.parent() {
        fs::create_dir_all(parent).unwrap_or(());
    }
    fs::write(&file_path, &form.data).unwrap_or(());

    // Firestore metadata stored with the same file_name
    let doc_ref = client.collection("uploads").doc(&form.file_name);
    let _ = doc_ref.set(serde_json::json!({ "path": file_path.to_string_lossy() })).await;
    HttpResponse::Ok().finish()
}

struct UploadForm {
    file_name: String,
    data: Vec<u8>,
}

In this example, if file_name is ../../../etc/passwd, the resolved path escapes /tmp/uploads. The Firestore document stores the unsafe path, which downstream consumers might use in an unsafe way. This demonstrates how a Zip Slip vector in Actix can coexist with Firestore usage, where the web framework is the weak link and Firestore becomes a storage point for potentially malicious references.

Remediation focuses on strict input validation and canonicalization before any path construction. The filename should be checked for traversal sequences, normalized, and confined to a safe directory. In Firestore, prefer using server-generated IDs or strictly validated document IDs rather than echoing user input. By addressing the path handling in Actix and ensuring Firestore metadata does not reflect untrusted paths, the attack surface is effectively mitigated.

Firestore-Specific Remediation in Actix — concrete code fixes

Secure handling requires two controls: (1) sanitize the filename in Actix before any filesystem interaction, and (2) avoid storing raw user input in Firestore fields that could be used in unsafe paths. Use a dedicated, server-side identifier for Firestore documents and keep filesystem paths strictly within a controlled directory.

First, validate and sanitize the filename. Strip traversal components and reject names that attempt to escape the target directory. A robust approach uses the canonicalize method after ensuring the path remains within the allowed base:

use actix_web::{post, web, HttpResponse};
use google_cloud_firestore::client::Client;
use std::path::{Path, PathBuf};
use std::fs;

fn safe_path(base: &Path, desired: &str) -> Option {
    let desired = desired.trim();
    if desired.is_empty() || desired.contains('\0') {
        return None;
    }
    // Reject obvious traversal patterns before joining
    if desired.contains("..") || desired.contains("..") {
        return None;
    }
    let full = base.join(desired);
    // Ensure the final path is within base
    full.strip_prefix(base).ok().map(|p| p.to_path_buf())
}

#[post("/upload")]
async fn upload_secure(
    form: web::Form,
    client: web::Data,
) -> HttpResponse {
    let base = Path::new("/tmp/uploads");
    let filename = match safe_path(base, &form.file_name) {
        Some(p) => p.file_name().unwrap().to_string_lossy().into_owned(),
        None => return HttpResponse::BadRequest().body("Invalid filename"),
    };
    let file_path = base.join(&filename);
    fs::create_dir_all(base).unwrap_or(());
    fs::write(&file_path, &form.data).unwrap_or(());

    // Use a server-generated or sanitized document ID; do not echo raw filename
    let doc_id = form.file_name.replace(|c: char| !c.is_alphanumeric(), "_");
    let doc_ref = client.collection("uploads").doc(&doc_id);
    let _ = doc_ref.set(serde_json::json!({ "stored_name": filename, "path": file_path.to_string_lossy() })).await;
    HttpResponse::Ok().finish()
}

struct UploadForm {
    file_name: String,
    data: Vec<u8>,
}

Second, when storing data in Firestore, avoid fields that mirror filesystem paths that could be abused later. Prefer stable identifiers and store only necessary metadata. If you must keep a reference to a filesystem location, ensure it is derived from a safe, canonical path and not directly from user input.

For continuous protection in pipelines, use the middleBrick CLI to scan your endpoints and verify that no path traversal risks remain:

middlebrick scan https://api.example.com

For teams integrating security into development workflows, the GitHub Action can enforce a minimum score before merges, while the MCP Server allows AI coding assistants to trigger scans without leaving the editor. These integrations support a defense-in-depth strategy by catching regressions early, complementing secure coding practices for Actix and Firestore integrations.

Frequently Asked Questions

Can Firestore itself be exploited via Zip Slip if I store user filenames as document IDs?
Firestore does not use a filesystem, so Zip Slip cannot occur inside Firestore itself. However, if your Actix service uses the same user input to build local filesystem paths before or after interacting with Firestore, the vulnerability exists at the filesystem boundary. Storing untrusted input as document IDs is generally safe for Firestore access control, but it may still lead to confusion or unsafe downstream usage if those IDs are later used to construct filesystem paths.
What is the best practice for filenames in Actix when working with Firestore?
Validate and sanitize filenames in Actix before any filesystem operation: reject or neutralize traversal sequences, restrict characters, and resolve paths against a strict base directory. Use server-generated or deterministic document IDs in Firestore rather than echoing raw filenames, and store only safe metadata. This reduces risk across both the web framework and the database layer.