HIGH zip slipginhmac signatures

Zip Slip in Gin with Hmac Signatures

Zip Slip in Gin with Hmac Signatures — how this specific combination creates or exposes the vulnerability

Zip Slip is a path traversal vulnerability that occurs when an archive entry name is not properly sanitized before extraction, allowing an attacker to write files outside the intended directory. In a Gin-based Go service that uses Hmac Signatures to verify the integrity of uploaded archives, the vulnerability can be introduced at the point where the signature is validated and the archive is processed, even though the signature itself is cryptographically sound.

Consider a scenario where a client uploads a ZIP file and provides an HMAC-SHA256 signature in a header. The server verifies the signature using a shared secret, then proceeds to extract the archive. If the server trusts the signature but does not validate the paths inside the archive, an attacker can craft a malicious ZIP containing files with paths like ../../../etc/passwd. The Hmac Signature check passes because the payload and signature match, but the extraction logic fails to enforce path safety. This means the presence of Hmac Signatures does not prevent Zip Slip; it only authenticates the data, not its safe handling.

In Gin, this typically occurs in a handler that reads the uploaded file, verifies the HMAC, and then uses a third-party archive library to extract contents. If the extraction function uses the entry name directly without cleaning or restricting it to a base directory, the application becomes vulnerable. The signature verification gives a false sense of security, because the integrity check is correctly implemented, but the unsafe extraction bypasses the intended security boundary. Real-world examples include archives with crafted filenames that traverse directory boundaries, leading to unauthorized file overwrites or information disclosure.

Common patterns that enable this include using zip.File.extract without path validation or using filepath.Join with user-supplied names without cleaning. Even with Hmac Signatures ensuring the data hasn't been tampered with in transit, the server must still treat archive contents as untrusted input. The vulnerability is not in the HMAC algorithm but in the failure to apply secure extraction practices after successful authentication.

Hmac Signatures-Specific Remediation in Gin — concrete code fixes

To remediate Zip Slip in Gin when Hmac Signatures are used, you must enforce strict path validation during archive extraction, independent of signature verification. The HMAC step confirms authenticity, but you must still sanitize and constrain file paths to prevent directory traversal.

Below is a secure Gin handler example that verifies an HMAC-SHA256 signature and then safely extracts a ZIP archive, ensuring no path escapes the target directory.

import (
    "archive/zip"
    "crypto/hmac"
    "crypto/sha256"
    "encoding/hex"
    "io"
    "net/http"
    "path/filepath"
    "strings"

    "github.com/gin-gonic/gin"
)

func verifyHMAC(data, signature, secret string) bool {
    key := []byte(secret)
    mac := hmac.New(sha256.New, key)
    mac.Write([]byte(data))
    expected := hex.EncodeToString(mac.Sum(nil))
    return hmac.Equal([]byte(expected), []byte(signature))
}

func extractZipSafe(srcPath, destDir string) error {
    r, err := zip.OpenReader(srcPath)
    if err != nil {
        return err
    }
    defer r.Close()

    for _, f := range r.File {
        // Clean and validate path
        upath := filepath.Clean(f.Name)
        if strings.HasPrefix(upath, "..") {
            return http.ErrAbortHandler
        }
        // Ensure the path stays within destDir
        if !strings.HasPrefix(upath, destDir) {
            return http.ErrAbortHandler
        }
        fullPath := filepath.Join(destDir, upath)

        if f.FileInfo().IsDir() {
            // Ensure directory path is safe before creating
            os.MkdirAll(fullPath, f.Mode())
            continue
        }

        if err := f.Open(); err != nil {
            return err
        }
        defer f.Close()

        dstFile, err := os.OpenFile(fullPath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, f.Mode())
        if err != nil {
            return err
        }
        defer dstFile.Close()

        if _, err := io.Copy(dstFile, f); err != nil {
            return err
        }
    }
    return nil
}

func UploadHandler(c *gin.Context) {
    file, header, err := c.Request.FormFile("archive")
    if err != nil {
        c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": "invalid file"})
        return
    }
    sig := c.GetHeader("X-Archive-Signature")
    // Compute data for HMAC (e.g., first 1KB or stream hash; here simplified)
    data, _ := io.ReadAll(file)
    if !verifyHMAC(string(data), sig, "your-secret") {
        c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"error": "invalid signature"})
        return
    }

    // Save temporarily and extract safely
    tmpFile := "/tmp/upload.zip"
    if err := c.SaveUploadedFile(header, tmpFile); err != nil {
        c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"error": "save failed"})
        return
    }
    if err := extractZipSafe(tmpFile, "/safe/extraction/dir"); err != nil {
        c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": "extraction blocked"})
        return
    }
    c.JSON(http.StatusOK, gin.H{"status": "ok"})
}

Key remediation steps:

  • Verify the HMAC before processing, but do not rely on it for path safety.
  • Use filepath.Clean on every entry name to eliminate .. sequences.
  • Ensure the cleaned path remains within the intended destination directory using a prefix check.
  • Use os.MkdirAll for directories and restrict file permissions to the minimum required.
  • Abort extraction immediately if any path validation fails, returning an appropriate error to the client.

By combining Hmac Signature verification with strict path sanitization, you maintain data integrity while eliminating the path traversal risk that enables Zip Slip.

Frequently Asked Questions

Does verifying an HMAC prevent Zip Slip in Gin handlers?
No. Hmac Signatures confirm data authenticity but do not validate archive paths. You must still sanitize and constrain extracted file paths to prevent traversal.
What is the essential step to secure archive extraction in Gin after HMAC verification?
Apply path cleaning with filepath.Clean and enforce that every resolved path remains within the intended extraction directory using a prefix check before creating files or directories.