HIGH zip slipecho gocockroachdb

Zip Slip in Echo Go with Cockroachdb

Zip Slip in Echo Go with Cockroachdb — how this specific combination creates or exposes the vulnerability

The combination of the Echo web framework, the Go programming language, and CockroachDB as the backend datastore can expose applications to Zip Slip when file extraction or archive processing occurs based on user-supplied paths. Zip Slip is a path traversal vulnerability that arises when an archive entry is extracted without proper validation, allowing absolute paths or sequences like ../ to traverse outside the intended extraction directory. In this stack, an API endpoint implemented in Echo that receives an uploaded archive (e.g., a ZIP file) and interacts with CockroachDB may inadvertently trust filenames stored in the archive or provided by the client.

Echo makes it straightforward to bind multipart form data to handler parameters, but if the handler directly uses archive entries to construct filesystem paths—especially to name derived records stored in CockroachDB—it can write files outside the target directory. For example, if the handler stores uploaded files on disk and also inserts a record into CockroachDB with the filename or path, an attacker can supply a malicious archive containing ../../etc/passwd or an absolute path. When the archive is extracted without canonicalization or validation, the traversal writes to sensitive locations. The application may then reference the attacker-controlled path when reading or writing data in CockroachDB, enabling unauthorized file access or overwriting critical system files.

Even when the database entry itself does not directly disclose file contents, Zip Slip can corrupt the application’s operational integrity: an attacker could overwrite application code or configuration files that CockroachDB-dependent services rely on. Because Echo routes are defined statically, a crafted path could also be used to overwrite route assets or templates if the application uses filesystem-based template loading. The vulnerability does not require authentication; it is triggered at the unauthenticated attack surface that middleBrick scans, testing endpoints that accept file uploads or archive processing without proper input validation.

In this context, the risk stems from insufficient validation of archive member paths before extraction and before persisting metadata to CockroachDB. The database becomes a secondary vector: if the application later queries files by user-supplied identifiers derived from the archive, it may inadvertently expose or manipulate unintended files. middleBrick’s checks for input validation and property authorization highlight these classes of issues by correling runtime behavior with the API specification, ensuring that path traversal and authorization flaws are surfaced regardless of the backend datastore.

Cockroachdb-Specific Remediation in Echo Go — concrete code fixes

Remediation centers on strict path sanitization before extraction and careful handling of filenames when storing metadata in CockroachDB. Always resolve archive member paths against a clean base directory and reject entries that escape that base. In Go, use filepath.Clean and filepath.Rel to detect traversal attempts, and avoid relying on filenames provided directly by the archive or client.

Below are concrete code examples for an Echo handler that uploads a ZIP archive, extracts it safely, and records file metadata in CockroachDB using the cockroachdb Go driver. The example demonstrates defense-in-depth with path validation, a clean base directory, and parameterized SQL to avoid injection while ensuring only intended files are persisted.

import (
    "archive/zip"
    "database/sql"
    "fmt"
    "io"
    "net/http"
    "os"
    "path/filepath"

    "github.com/labstack/echo/v4"
    _ "github.com/lib/pq"
)

const baseDir = "/srv/app/uploads"

func uploadAndStore(c echo.Context) error {
    file, err := c.FormFile("archive")
    if err != nil {
        return echo.NewHTTPError(http.StatusBadRequest, "archive required")
    }

    src, err := file.Open()
    if err != nil {
        return echo.NewHTTPError(http.StatusInternalServerError, "failed to open archive")
    }
    defer src.Close()

    zipReader, err := zip.NewReader(src, file.Size)
    if err != nil {
        return echo.NewHTTPError(http.StatusBadRequest, "invalid archive")
    }

    db, err := sql.Open("postgres", os.Getenv("COCKROACHDB_URL"))
    if err != nil {
        return echo.NewHTTPError(http.StatusInternalServerError, "database unavailable")
    }
    defer db.Close()

    for _, f := range zipReader.File {
        // Zip Slip mitigation: clean and verify path
        dstPath := filepath.Join(baseDir, f.Name)
        if !isWithinBase(dstPath, baseDir) {
            return echo.NewHTTPError(http.StatusBadRequest, "invalid file path in archive")
        }

        if f.FileInfo().IsDir() {
            os.MkdirAll(dstPath, os.ModePerm)
            continue
        }

        rc, err := f.Open()
        if err != nil {
            continue
        }
        defer rc.Close()

        dstFile, err := os.OpenFile(dstPath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, f.Mode())
        if err != nil {
            return echo.NewHTTPError(http.StatusInternalServerError, "failed to create file")
        }
        _, err = io.Copy(dstFile, rc)
        dstFile.Close()
        if err != nil {
            return echo.NewHTTPError(http.StatusInternalServerError, "failed to write file")
        }

        // Persist metadata safely; use parameterized queries to avoid SQL injection
        _, err = db.Exec("INSERT INTO uploaded_files (name, path, size) VALUES ($1, $2, $3)",
            f.Name, dstPath, f.UncompressedSize64)
        if err != nil {
            return echo.NewHTTPError(http.StatusInternalServerError, "failed to store metadata")
        }
    }
    return c.NoContent(http.StatusCreated)
}

func isWithinBase(full, base string) bool {
    rel, err := filepath.Rel(base, full)
    if err != nil {
        return false
    }
    return rel != ".." && rel[:2] != ".." // reject paths that escape base
}

Key points specific to this stack:

  • Validate on extraction: use isWithinBase to ensure no member resolves outside baseDir. This prevents Zip Slip regardless of how paths are stored in the archive.
  • Separate storage from metadata: store files under cleaned paths and only persist metadata (e.g., original name, size) in CockroachDB using parameterized queries. Do not trust f.Name for filesystem operations without sanitization.
  • Limit filesystem exposure: even when serving files, resolve paths through the same base check before sending content to the client, preventing traversal via crafted URLs or IDs derived from the database.

By combining strict path validation in Echo handlers with safe database interactions, the stack mitigates Zip Slip while preserving the ability to use CockroachDB for reliable metadata storage. This approach aligns with input validation and property authorization checks emphasized by middleBrick, ensuring that both filesystem and database boundaries are respected.

Frequently Asked Questions

Can Zip Slip be exploited through CockroachDB queries even when files are stored safely?
Yes, if the application later uses user-supplied values to locate files and those values are concatenated into paths or SQL statements without validation, traversal can still occur. Always sanitize and validate any path derived from archive metadata or client input before filesystem or database operations.
Does middleBrick detect Zip Slip in APIs that use CockroachDB?
middleBrick tests input validation and property authorization as part of its 12 checks. It correlates runtime behavior with API specifications to identify path traversal risks, regardless of whether the backend is CockroachDB or another datastore, and provides remediation guidance.