HIGH zip slipaspnetfirestore

Zip Slip in Aspnet with Firestore

Zip Slip in Aspnet 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 archive entries without proper validation, enabling path traversal (e.g., ../../../etc/passwd). In an ASP.NET context, this risk is amplified when the application uses Google Cloud Firestore to store or serve file metadata, such as user-uploaded document references, without validating the resulting paths. Consider an endpoint that receives a Firestore document ID and a filename from a client, then constructs a local or cloud storage path to serve the file. If the filename is taken directly from archive contents (e.g., a ZIP uploaded and extracted server-side) and concatenated with a base path, an attacker can supply filenames like ../../../../../../windows/win.ini to escape intended directories.

Firestore itself does not execute files, but it often acts as a catalog for user content. When an ASP.NET app stores user-provided filenames or paths in Firestore and later uses them to build local filesystem paths or signed download URLs, the lack of path normalization and validation introduces a classic Zip Slip vector. For example, a malicious archive containing entries such as ../../../secrets/appsettings.json can escape a temporary extraction folder and overwrite arbitrary files if the server uses naive path joining. Even when Firestore stores only metadata (e.g., bucket and object names), unsafe consumption of user input allows attackers to manipulate path resolution downstream, leading to unauthorized file reads or overwrites.

To detect this pattern, middleBrick scans ASP.NET endpoints that interact with Firestore for unsafe input handling and path construction across the 12 security checks, including Input Validation, Property Authorization, and Unsafe Consumption. Findings include evidence of unsanitized filename usage, missing path canonicalization, and gaps in authorization checks that could permit path traversal. Remediation guidance emphasizes validating and sanitizing all user-supplied path components, using language-level path normalization, and avoiding direct concatenation of user input into filesystem or bucket paths.

Firestore-Specific Remediation in Aspnet — concrete code fixes

Secure handling of paths in ASP.NET applications that use Firestore requires strict input validation, canonicalization, and scoping to user-permitted directories. Below are concrete, safe patterns for working with Firestore metadata and file paths.

1. Validate and canonicalize paths before using them

Always resolve paths with Path.GetFullPath and ensure they remain within an allowed base directory. Do not trust Firestore-stored paths or filenames directly.

using System;
using System.IO;

public bool IsPathSafe(string baseDirectory, string userSuppliedPath)
{
    string fullPath = Path.GetFullPath(Path.Combine(baseDirectory, userSuppliedPath));
    return fullPath.StartsWith(baseDirectory, StringComparison.OrdinalIgnoreCase);
}

// Example usage:
string baseDir = "/safe/uploads";
string candidate = Path.Combine(baseDir, userSuppliedPath);
if (!IsPathSafe(baseDir, candidate))
{
    throw new UnauthorizedAccessException("Invalid path.");
}

2. Use Firestore to store references, not executable paths

Store minimal, validated metadata in Firestore. Avoid persisting raw filenames or paths that can be concatenated into filesystem operations. Use generated identifiers and map them to secure download logic server-side.

using Google.Cloud.Firestore;
using System;

public class DocumentRecord
{
    [FirestoreProperty]
    public string FileId { get; set; }

    [FirestoreProperty]
    public string OriginalFileName { get; set; }
}

// Sanitize filename before storing
public string SanitizeFileName(string name)
{
    string fileName = Path.GetFileName(name ?? "");
    if (string.IsNullOrWhiteSpace(fileName))
        throw new ArgumentException("Invalid filename.");
    // Remove path characters and reserved names
    string invalid = Path.GetInvalidFileNameChars().Aggregate(fileName, (current, c) => current.Replace(c.ToString(), string.Empty));
    return invalid.Trim();
}

// Store safely
var doc = new DocumentRecord { FileId = Guid.NewGuid().ToString(), OriginalFileName = SanitizeFileName(userFileName) };
await db.Collection("documents").AddAsync(doc);

3. Serve files via controlled endpoints, not direct path concatenation

Instead of building filesystem paths from Firestore metadata, use signed URLs or a controller that maps allowed IDs to storage objects, ensuring path traversal is impossible.

using Google.Cloud.Storage.V1;
using Microsoft.AspNetCore.Mvc;

[ApiController]
[Route("api/files")]
public class FilesController : ControllerBase
{
    private readonly StorageClient _storageClient;
    private readonly string _bucketName = "my-secure-bucket";

    public FilesController(StorageClient storageClient)
    {
        _storageClient = storageClient;
    }

    [HttpGet("{fileId}")]
    public async Task GetFile(string fileId)
    {
        // Lookup file metadata from Firestore using fileId
        var doc = await db.Collection("documents").Document(fileId).GetSnapshotAsync();
        if (!doc.Exists)
            return NotFound();

        var fileName = doc.ConvertTo().OriginalFileName;
        // Use fileName only for safe Content-Disposition; do not join with paths
        var memoryStream = new MemoryStream();
        await _storageClient.DownloadObjectAsync(_bucketName, fileName, memoryStream);
        memoryStream.Seek(0, SeekOrigin.Begin);
        return File(memoryStream.ToArray(), "application/octet-stream", fileName);
    }
}

4. Harden ZIP extraction in ASP.NET

When extracting user-provided archives, use a library that prevents path traversal (e.g., ensure entries are resolved against a base directory and reject entries with PathTraversal patterns). Do not use raw ZipArchive without validation.

using System.IO.Compression;

public void SafeExtractZip(Stream zipStream, string outputFolder)
{
    using var archive = new ZipArchive(zipStream);
    foreach (var entry in archive.Entries)
    {
        string destinationPath = Path.GetFullPath(Path.Combine(outputFolder, entry.FullName));
        if (!destinationPath.StartsWith(outputFolder, StringComparison.OrdinalIgnoreCase))
            throw new InvalidDataException("Invalid ZIP entry: path traversal detected.");
        entry.ExtractToFile(destinationPath, overwrite: true);
    }
}

5. Apply defense-in-depth with middleware

Add request validation middleware to reject suspicious paths early and enforce strict content-type and size limits for uploads involving Firestore references.

app.Use(async (context, next) =>
{
    if (context.Request.Path.StartsWithSegments("/api/files"))
    {
        // Example: reject paths containing traversal patterns
        if (context.Request.QueryString.Value != null &&
            (context.Request.QueryString.Value.Contains("..") || context.Request.QueryString.Value.Contains(":")))
        {
            context.Response.StatusCode = 400;
            return;
        }
    }
    await next();
});

Frequently Asked Questions

How does middleBrick detect Zip Slip risks in ASP.NET endpoints that use Firestore?
middleBrick runs parallel security checks including Input Validation, Unsafe Consumption, and Property Authorization. It analyzes OpenAPI specs and runtime behavior to identify unsafe path concatenation, missing canonicalization, and Firestore metadata patterns that could enable path traversal.
Does middleBrick fix Zip Slip issues automatically?
middleBrick detects and reports findings with remediation guidance. It does not automatically patch code; developers should apply secure path validation, canonicalization, and controlled file-serving patterns as shown in the remediation examples.