Zip Slip in Fiber
How Zip Slip Manifests in Fiber
Zip Slip is a path traversal vulnerability that occurs when an application extracts files from a ZIP archive without validating the file paths within the archive. In Fiber applications, this manifests through several specific patterns that developers should be aware of.
The most common Fiber-specific manifestation occurs in file upload handlers where users can submit ZIP archives. Consider this vulnerable pattern:
func uploadZip(c *fiber.Ctx) error {
// Parse the multipart form
err := c.BodyParser(&payload)
if err != nil { return err }
// Read the uploaded file
file, err := c.FormFile("file")
if err != nil { return err }
// Save to disk
src, err := file.Open()
if err != nil { return err }
defer src.Close()
// Create a zip reader
zipReader, err := zip.NewReader(src, file.Size)
if err != nil { return err }
// Extract all files without validation
for _, f := range zipReader.File {
rc, err := f.Open()
if err != nil { return err }
defer rc.Close()
// Create target path
targetPath := filepath.Join("./uploads", f.Name)
// Write file to disk
out, err := os.Create(targetPath)
if err != nil { return err }
defer out.Close()
io.Copy(out, rc)
}
return c.JSON(fiber.Map{"message": "Files extracted successfully"})
}
The critical vulnerability here is filepath.Join("./uploads", f.Name). If an attacker includes a file named ../../etc/passwd in their ZIP archive, the filepath.Join function will resolve this to a path outside the intended upload directory, potentially overwriting system files or accessing sensitive data.
Another Fiber-specific pattern involves middleware that handles file processing:
func FileProcessorMiddleware(next fiber.Handler) fiber.Handler {
return func(c *fiber.Ctx) error {
// Check if file was uploaded
if c.Get("Content-Type") == "application/zip" {
// Extract and process ZIP
file, err := c.FormFile("archive")
if err != nil { return err }
// Dangerous extraction without validation
extractZip(file)
}
return next(c)
}
}
Attackers can craft ZIP archives with files like ../config.json, ../../secret.key, or even ../../../../../../etc/passwd to traverse directory structures and overwrite critical files.
Fiber-Specific Detection
Detecting Zip Slip vulnerabilities in Fiber applications requires both manual code review and automated scanning. Here are Fiber-specific detection methods:
Manual Code Review Patterns
Look for these specific patterns in your Fiber codebase:
# Search for dangerous patterns
grep -r "zip\.NewReader" . --include="*.go"
grep -r "filepath\.Join" . --include="*.go" | grep -E "(\.Name|filename)"
grep -r "os\.Create" . --include="*.go" | grep -E "(\.Name|filename)"
Focus on handlers that accept file uploads and process ZIP archives. The vulnerable pattern typically involves:
- Accepting multipart form data with
c.FormFile() - Creating a
zip.NewReaderfrom the uploaded file - Iterating through
zipReader.Filewithout path validation - Using
filepath.Joinwith user-controlled filenames
middleBrick Security Scanning
middleBrick provides Fiber-specific Zip Slip detection through its black-box scanning approach. Unlike source code analysis tools, middleBrick tests the actual running API endpoints:
# Scan your Fiber API with middleBrick
middlebrick scan https://yourapi.com/upload-zip
middleBrick tests for Zip Slip by:
- Submitting crafted ZIP archives with traversal paths
- Verifying if extracted files appear outside the intended directory
- Checking for successful path traversal attempts
- Mapping findings to OWASP API Top 10 (A1: Injection, A4: Path Traversal)
The scanner provides a security score with specific findings like:
{
"severity": "high",
"category": "Path Traversal",
"finding": "Zip Slip vulnerability in /api/upload-zip endpoint",
"remediation": "Validate file paths before extraction and sanitize filenames",
"cve_reference": "CVE-2018-1000533"
}
Static Analysis with golangci-lint
Configure golangci-lint to catch potential Zip Slip patterns:
# .golangci.yml
linters:
enable:
- gosec
- staticcheck
run:
skip-dirs:
- vendor
- node_modules
issues:
exclude-use-default: false
Add custom checks for dangerous patterns or use security-focused linters that can detect path traversal vulnerabilities.
Fiber-Specific Remediation
Remediating Zip Slip vulnerabilities in Fiber applications requires implementing proper path validation and secure file handling practices. Here are Fiber-specific solutions:
Path Validation Before Extraction
The most critical fix is validating file paths before extraction:
import (
"path/filepath"
"strings"
"github.com/gofiber/fiber"
)
func validateZipPath(baseDir, zipPath string) (string, error) {
// Clean and normalize the path
cleanPath := filepath.Clean(zipPath)
// Check for path traversal
if strings.Contains(cleanPath, "..") {
return "", fiber.NewError(fiber.StatusBadRequest, "Invalid file path")
}
// Ensure path is within base directory
targetPath := filepath.Join(baseDir, cleanPath)
if !strings.HasPrefix(targetPath, filepath.Clean(baseDir)) {
return "", fiber.NewError(fiber.StatusBadRequest, "Path traversal detected")
}
return targetPath, nil
}
func secureUploadZip(c *fiber.Ctx) error {
file, err := c.FormFile("file")
if err != nil { return err }
src, err := file.Open()
if err != nil { return err }
defer src.Close()
zipReader, err := zip.NewReader(src, file.Size)
if err != nil { return err }
baseDir := "./secure-uploads"
os.MkdirAll(baseDir, 0755)
for _, f := range zipReader.File {
targetPath, err := validateZipPath(baseDir, f.Name)
if err != nil {
return err
}
// Create directories if needed
os.MkdirAll(filepath.Dir(targetPath), 0755)
rc, err := f.Open()
if err != nil { return err }
defer rc.Close()
out, err := os.Create(targetPath)
if err != nil { return err }
defer out.Close()
io.Copy(out, rc)
}
return c.JSON(fiber.Map{"message": "Files extracted securely"})
}
Filename Sanitization
Sanitize filenames to prevent malicious path components:
func sanitizeFilename(name string) string {
// Remove path traversal patterns
clean := filepath.Clean(name)
// Remove any remaining dangerous characters
clean = strings.ReplaceAll(clean, "../", "")
clean = strings.ReplaceAll(clean, "..\\", "")
// Only allow alphanumeric, dash, underscore, dot
var allowed []rune
for _, r := range clean {
if (r >= 'a' && r <= 'z') ||
(r >= 'A' && r <= 'Z') ||
(r >= '0' && r <= '9') ||
r == '-' || r == '_' || r == '.' || r == '/' {
allowed = append(allowed, r)
}
}
return string(allowed)
}
func uploadWithSanitization(c *fiber.Ctx) error {
file, err := c.FormFile("archive")
if err != nil { return err }
src, err := file.Open()
if err != nil { return err }
defer src.Close()
zipReader, err := zip.NewReader(src, file.Size)
if err != nil { return err }
baseDir := "./sanitized-uploads"
os.MkdirAll(baseDir, 0755)
for _, f := range zipReader.File {
sanitizedName := sanitizeFilename(f.Name)
targetPath := filepath.Join(baseDir, sanitizedName)
// Additional validation
if !strings.HasPrefix(targetPath, filepath.Clean(baseDir)) {
return fiber.NewError(fiber.StatusBadRequest, "Invalid filename")
}
rc, err := f.Open()
if err != nil { return err }
defer rc.Close()
out, err := os.Create(targetPath)
if err != nil { return err }
defer out.Close()
io.Copy(out, rc)
}
return c.JSON(fiber.Map{"message": "Files extracted with sanitization"})
}
Using Temporary Directories
Isolate extracted files in temporary directories:
import (
"io/ioutil"
"os"
"github.com/gofiber/fiber"
)
func extractToTemp(c *fiber.Ctx) error {
file, err := c.FormFile("file")
if err != nil { return err }
src, err := file.Open()
if err != nil { return err }
defer src.Close()
// Create a unique temporary directory
tempDir, err := ioutil.TempDir("", "fiber-upload-*")
if err != nil { return err }
defer os.RemoveAll(tempDir)
zipReader, err := zip.NewReader(src, file.Size)
if err != nil { return err }
for _, f := range zipReader.File {
// Clean and validate path
cleanName := filepath.Clean(f.Name)
if strings.Contains(cleanName, "..") {
return fiber.NewError(fiber.StatusBadRequest, "Invalid file path")
}
targetPath := filepath.Join(tempDir, cleanName)
// Create directories
os.MkdirAll(filepath.Dir(targetPath), 0755)
rc, err := f.Open()
if err != nil { return err }
defer rc.Close()
out, err := os.Create(targetPath)
if err != nil { return err }
defer out.Close()
io.Copy(out, rc)
}
// Process files from tempDir
return c.JSON(fiber.Map{"message": "Files extracted to temp directory"})
}
Integration with middleBrick
After implementing these fixes, verify your remediation with middleBrick:
# Run middleBrick scan after fixes
middlebrick scan https://yourapi.com/upload-zip --fail-on-high-risk
# Check the report for Zip Slip findings
middlebrick report last --format=json | jq '.findings[] | select(.category == "Path Traversal")'
middleBrick's continuous monitoring (Pro plan) can automatically scan your API endpoints on a schedule, ensuring that Zip Slip vulnerabilities don't reappear as your codebase evolves.
Frequently Asked Questions
How can I test if my Fiber API is vulnerable to Zip Slip?
../../test.txt or ../../../../etc/passwd. Upload it to your Fiber endpoint and check if the files are extracted outside the intended directory. You can also use middleBrick's automated scanning which specifically tests for Zip Slip vulnerabilities by submitting crafted ZIP archives and verifying path traversal attempts.