Zip Slip in Echo Go
How Zip Slip Manifests in Echo Go
Zip Slip in Echo Go applications typically occurs when handling file uploads through multipart form data. The vulnerability arises when an attacker crafts a ZIP archive containing files with malicious path traversal sequences like ../../ or absolute paths that, when extracted, overwrite critical files outside the intended directory.
In Echo Go, this often manifests in API endpoints that accept ZIP uploads for processing. Consider this vulnerable pattern:
func uploadZip(c echo.Context) 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, int64(file.Size))
if err != nil { return err }
// Vulnerable: no path sanitization
for _, f := range zipReader.File {
rc, err := f.Open()
if err != nil { return err }
defer rc.Close()
destPath := filepath.Join("uploads", f.Name)
os.MkdirAll(filepath.Dir(destPath), 0755)
outFile, err := os.Create(destPath)
if err != nil { return err }
defer outFile.Close()
io.Copy(outFile, rc)
}
return c.String(http.StatusOK, "Upload successful")
}The critical flaw is on line 13 where f.Name is used directly without sanitization. An attacker could upload a ZIP containing ../../config.yaml which would resolve to the parent directory of uploads, potentially overwriting configuration files or even binary executables if the application has sufficient permissions.
Another Echo Go-specific manifestation occurs when handling template files or configuration uploads. If an Echo application allows uploading template ZIPs for dynamic rendering, Zip Slip could allow an attacker to inject malicious templates that execute arbitrary code when rendered:
func uploadTemplates(c echo.Context) error {
// Similar vulnerable pattern
// Attacker could overwrite core template files
// leading to template injection vulnerabilities
}The risk is amplified in Echo Go applications because Echo's template system (using github.com/labstack/echo/v4/template) will automatically reload templates when files change, meaning malicious templates could execute immediately after being written.
Echo Go-Specific Detection
Detecting Zip Slip in Echo Go applications requires both static analysis and runtime scanning. For static detection, look for these patterns in your codebase:
# Search for vulnerable zip handling patterns
grep -r "zip\.NewReader" . --include="*.go"
grep -r "FormFile" . --include="*.go" | grep -i zip
Focus on endpoints that handle multipart/form-data and check if they extract files without path validation. The most dangerous pattern is joining user-controlled paths with filepath.Join without sanitization.
For runtime detection, middleBrick's black-box scanning can identify Zip Slip vulnerabilities in Echo Go APIs without requiring source code access. middleBrick tests for this by:
- Crafting ZIP archives with traversal sequences like
../../test.txt - Uploading to multipart endpoints and observing file system access
- Checking if files are written outside the intended directory
- Verifying if the application handles path traversal gracefully
- Scanning for exposed sensitive files that might have been overwritten
middleBrick's scanning process specifically tests Echo Go's file handling by simulating attacker behavior. It creates ZIP archives with various traversal patterns and monitors the server's response to determine if path traversal succeeds. The scanner also checks if the application properly validates file extensions and MIME types, which are common secondary controls that might be missing.
Additionally, middleBrick analyzes OpenAPI specifications to understand the expected file handling behavior and then tests against that contract. For Echo Go applications that expose their API specs, this provides even more accurate vulnerability detection.
Echo Go-Specific Remediation
Remediating Zip Slip in Echo Go requires implementing proper path validation and safe extraction practices. Here's the secure approach using Echo Go's native capabilities:
import (
"archive/zip"
"path/filepath"
"github.com/labstack/echo/v4"
)
func safeUploadZip(c echo.Context) error {
file, err := c.FormFile("file")
if err != nil {
return echo.NewHTTPError(http.StatusBadRequest, "Missing file")
}
// Validate file type by extension and MIME
if filepath.Ext(file.Filename) != ".zip" {
return echo.NewHTTPError(http.StatusBadRequest, "Only ZIP files allowed")
}
src, err := file.Open()
if err != nil {
return err
}
defer src.Close()
zipReader, err := zip.NewReader(src, int64(file.Size))
if err != nil {
return echo.NewHTTPError(http.StatusBadRequest, "Invalid ZIP file")
}
// Define safe extraction directory
const extractDir = "safe_uploads"
os.MkdirAll(extractDir, 0755)
for _, zf := range zipReader.File {
// Critical: validate file name
if zf.Name.Contains("..") || filepath.IsAbs(zf.Name) {
return echo.NewHTTPError(http.StatusBadRequest, "Invalid file path in ZIP")
}
// Additional validation: check for dangerous file types
if filepath.Ext(zf.Name) == ".exe" || filepath.Ext(zf.Name) == ".bat" {
return echo.NewHTTPError(http.StatusBadRequest, "Executable files not allowed")
}
// Sanitize and create safe path
safePath := filepath.Join(extractDir, zf.Name)
if !strings.HasPrefix(safePath, filepath.Clean(extractDir)+string(filepath.Separator)) {
return echo.NewHTTPError(http.StatusBadRequest, "Path traversal attempt detected")
}
// Create directories safely
os.MkdirAll(filepath.Dir(safePath), 0755)
// Extract file
rc, err := zf.Open()
if err != nil {
return err
}
defer rc.Close()
outFile, err := os.Create(safePath)
if err != nil {
return err
}
defer outFile.Close()
if _, err := io.Copy(outFile, rc); err != nil {
return err
}
}
return c.String(http.StatusOK, "Upload successful and extracted safely")
}Key security improvements in this Echo Go-specific remediation:
- Path validation: Checks for
..sequences and absolute paths before extraction - Safe prefix verification: Ensures the resolved path stays within the intended directory using prefix checking
- File type restrictions: Blocks potentially dangerous file extensions
- Cleaned paths: Uses
filepath.Cleanto normalize paths before validation
For Echo Go applications using the Echo framework's middleware system, you can also implement a middleware that validates all file uploads:
func zipSlipValidator() echo.MiddlewareFunc {
return func(next echo.HandlerFunc) echo.HandlerFunc {
return func(c echo.Context) error {
if c.Request().MultipartForm != nil {
for _, fileHeaders := range c.Request().MultipartForm.File {
for _, fh := range fileHeaders {
if filepath.Ext(fh.Filename) == ".zip" {
// Mark for special validation
c.Set("zipFileUploaded", true)
}
}
}
}
return next(c)
}
}
}
// Apply middleware globally
e := echo.New()
e.Use(zipSlipValidator())
This middleware approach allows you to centralize ZIP file validation across all Echo Go endpoints, ensuring consistent security enforcement throughout your application.
Frequently Asked Questions
How can I test if my Echo Go application is vulnerable to Zip Slip?
../../test.txt and upload it to your file upload endpoints. Monitor if the files are extracted outside the intended directory. For comprehensive testing, use middleBrick's black-box scanning which automatically tests for Zip Slip vulnerabilities without requiring source code access.