Symlink Attack in Fiber
How Symlink Attack Manifests in Fiber
Symlink attacks in Fiber applications typically exploit the framework's file handling capabilities, particularly when serving user-uploaded content or processing file paths. These attacks occur when an attacker creates symbolic links that point to sensitive files or directories outside the intended scope.
In Fiber, symlink attacks often manifest through path traversal vulnerabilities combined with symbolic link resolution. For example, when Fiber serves files using c.Context().SendFile() or similar methods, an attacker might upload a malicious symlink that points to /etc/passwd or other sensitive system files.
A common Fiber-specific scenario involves file upload endpoints. Consider this vulnerable pattern:
func uploadFile(c *fiber.Ctx) error {
file, err := c.FormFile("file")
if err != nil {
return err
}
// Vulnerable: no symlink check
c.SaveFile(file, fmt.Sprintf("./uploads/%s", file.Filename))
return c.JSON(fiber.Map{"message": "success"})
}An attacker could upload a file named ../../../../etc/passwd or create a symlink that resolves to sensitive system files. Fiber's default file handling doesn't automatically resolve symlinks, but when combined with other filesystem operations, this can lead to information disclosure.
Another manifestation occurs in API endpoints that process file paths dynamically. For instance:
func getFile(c *fiber.Ctx) error {
filePath := c.Params("path")
// Vulnerable: no path validation
return c.SendFile(filePath)
}Here, an attacker could request /api/files/../../../etc/passwd, potentially accessing files outside the intended directory. While Fiber's SendFile method has some built-in protections, improper validation can still lead to symlink-based attacks.
Symlink attacks in Fiber are particularly dangerous when combined with race conditions. An attacker might create a symlink, trigger the vulnerable endpoint, and then quickly replace the symlink target before the application reads it. This time-of-check-to-time-of-use (TOCTOU) vulnerability can bypass simple existence checks.
Fiber-Specific Detection
Detecting symlink attacks in Fiber applications requires both static code analysis and runtime monitoring. For static detection, middleBrick's API security scanner specifically checks for vulnerable file handling patterns in Fiber applications.
middleBrick scans Fiber endpoints by analyzing the runtime behavior of file-serving endpoints. It tests for symlink vulnerabilities by attempting to access files through path traversal sequences like ../../ and checking if the application resolves these to sensitive files. The scanner also tests for race conditions by creating temporary symlinks and monitoring how the application handles them.
Key detection patterns middleBrick looks for in Fiber applications:
- Endpoints using
c.SendFile()orc.SaveFile()without proper path validation - File upload handlers that don't check for symlink creation
- Dynamic path resolution based on user input
- Missing
filepath.Clean()or similar sanitization - Race condition vulnerabilities in file operations
For manual detection, you can implement runtime checks in your Fiber application:
func safeSendFile(c *fiber.Ctx, filePath string) error {
// Resolve symlinks and check if path is within allowed directory
realPath, err := filepath.Abs(filePath)
if err != nil {
return c.Status(400).JSON(fiber.Map{"error": "invalid path"})
}
// Define allowed directory
allowedDir, _ := filepath.Abs("./uploads/")
// Check if resolved path is within allowed directory
if !strings.HasPrefix(realPath, allowedDir) {
return c.Status(403).JSON(fiber.Map{"error": "access denied"})
}
return c.SendFile(realPath)
}middleBrick's continuous monitoring (available in Pro plan) can automatically detect when new symlink vulnerabilities are introduced in your Fiber codebase by scanning your API endpoints on a configurable schedule and alerting you to any regression in security posture.
Fiber-Specific Remediation
Remediating symlink attacks in Fiber requires a defense-in-depth approach. Here are Fiber-specific fixes for common vulnerability patterns:
For file upload endpoints, implement strict filename validation and symlink detection:
func secureUpload(c *fiber.Ctx) error {
file, err := c.FormFile("file")
if err != nil {
return c.Status(400).JSON(fiber.Map{"error": "invalid file"})
}
// Validate filename - no path traversal characters
if strings.Contains(file.Filename, "..") || strings.Contains(file.Filename, "/") {
return c.Status(400).JSON(fiber.Map{"error": "invalid filename"})
}
// Save to uploads directory with clean path
uploadPath := filepath.Join("./uploads", file.Filename)
// Check if file is a symlink before saving
if isSymlink(uploadPath) {
return c.Status(400).JSON(fiber.Map{"error": "symlink not allowed"})
}
c.SaveFile(file, uploadPath)
return c.JSON(fiber.Map{"message": "upload successful"})
}
func isSymlink(path string) bool {
fileInfo, err := os.Lstat(path)
if err != nil {
return false
}
return fileInfo.Mode()&os.ModeSymlink != 0
}For dynamic file serving, use Fiber's built-in path validation and add additional checks:
func secureServeFile(c *fiber.Ctx) error {
filePath := c.Params("path")
// Clean the path to prevent traversal
cleanPath := filepath.Clean(filePath)
// Resolve to absolute path within uploads directory
baseDir := filepath.Clean("./uploads")
targetPath := filepath.Join(baseDir, cleanPath)
// Verify the resolved path is within the base directory
if !strings.HasPrefix(targetPath, baseDir+string(filepath.Separator)) {
return c.Status(403).JSON(fiber.Map{"error": "forbidden"})
}
// Check if target is a symlink
if isSymlink(targetPath) {
return c.Status(403).JSON(fiber.Map{"error": "symlink not allowed"})
}
return c.SendFile(targetPath)
}For race condition protection, use atomic file operations and validate file integrity:
func atomicFileOperation(c *fiber.Ctx) error {
tempFile, err := os.CreateTemp("./uploads", "temp_*.dat")
if err != nil {
return err
}
defer os.Remove(tempFile.Name())
// Write data to temp file
_, err = tempFile.Write([]byte("sensitive data"))
if err != nil {
return err
}
tempFile.Close()
// Atomic rename - prevents symlink replacement during operation
finalPath := filepath.Join("./uploads", "final.dat")
err = os.Rename(tempFile.Name(), finalPath)
if err != nil {
return err
}
// Verify file integrity after operation
if isSymlink(finalPath) {
os.Remove(finalPath)
return c.Status(500).JSON(fiber.Map{"error": "file integrity compromised"})
}
return c.JSON(fiber.Map{"message": "operation completed"})
}middleBrick's GitHub Action can automatically scan your Fiber application during CI/CD pipelines, ensuring these remediation patterns are consistently applied across your codebase and preventing symlink vulnerabilities from reaching production.