Zip Slip in Fiber with Dynamodb
Zip Slip in Fiber with Dynamodb — how this specific combination creates or exposes the vulnerability
Zip Slip is a path traversal vulnerability that occurs when an application constructs file paths from user-supplied input without proper validation. In a Go Fiber application that interacts with Amazon DynamoDB, the risk emerges at the intersection of HTTP request handling, file system operations, and data modeling choices in DynamoDB.
Consider a scenario where a Fiber handler accepts a filename or key from a client and uses it to read or write objects in DynamoDB, then later performs filesystem operations based on that key. If the input is not strictly validated, an attacker can provide a specially crafted value such as ../../../etc/passwd. When the application uses standard path joining (for example, filepath.Join(uploadDir, userInput)) without cleaning or restricting path segments, the resulting path escapes the intended directory. This allows reading or overwriting arbitrary files on the host, which can lead to information disclosure or code execution depending on the runtime context.
DynamoDB itself does not execute paths, but it can store metadata or keys that later influence file system behavior. For example, an item might contain an attachmentKey attribute that the application uses to build local file paths. If the application trusts this stored value and uses it directly in path operations without sanitization, the DynamoDB entry becomes a vector for persisted malicious payloads. Additionally, if the application uses DynamoDB conditional writes or streams to trigger downstream processing (e.g., invoking local scripts or parsers), crafted input stored in DynamoDB can be executed in a vulnerable context when the processing logic builds file paths unsafely.
The combination is particularly dangerous because Fiber’s performance and simplicity can encourage developers to skip rigorous input validation, assuming that DynamoDB acts as a safe, structured store. However, DynamoDB only enforces constraints you define; if your data model does not restrict path-like attributes, and your application code performs unsafe path concatenation, the vulnerability exists at the application layer, not the database layer. Attackers exploit this by sending malicious HTTP requests that leverage the Fiber route handling, ultimately manipulating local filesystem paths through unchecked values originating from or influenced by DynamoDB-stored data.
Dynamodb-Specific Remediation in Fiber — concrete code fixes
To remediate Zip Slip in a Fiber application that uses DynamoDB, you must validate and sanitize any path derived from user input or from data stored in DynamoDB before using it in filesystem operations. Below are concrete code examples for a Fiber handler that safely manages file keys while interacting with DynamoDB.
First, define a strict allowlist for filenames and use path.Clean and filepath.Rel to ensure paths remain within the intended directory. Combine this with parameterized DynamoDB operations to avoid injection of malicious metadata.
// main.go
package main
import (
"fmt"
"net/http"
"path/filepath"
"strings"
"github.com/gofiber/fiber/v2"
"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/config"
"github.com/aws/aws-sdk-go-v2/service/dynamodb"
"github.com/aws/aws-sdk-go-v2/service/dynamodb/types"
)
func main() {
app := fiber.New()
// Load AWS config (assumes proper environment or IAM configuration)
cfg, err := config.LoadDefaultConfig(app.Context())
if err != nil {
panic(fmt.Errorf("unable to load SDK config: %w", err))
}
client := dynamodb.NewFromConfig(cfg)
app.Post("/upload", func(c *fiber.Ctx) error {
// Expect JSON: { "key": "user123/report.txt" }
type RequestBody struct {
Key string `json:"key"`
}
var body RequestBody
if err := c.BodyParser(&body); err != nil {
return c.Status(http.StatusBadRequest).JSON(fiber.Map{"error": "invalid request body"})
}
// Validate key: allow only alphanumeric, underscores, hyphens, and a single dot for extension
if !isValidKey(body.Key) {
return c.Status(http.StatusBadRequest).JSON(fiber.Map{"error": "invalid key format"})
}
// Ensure the key is relative and does not escape the base directory
base := "uploads"
cleanKey := filepath.Clean("/" + body.Key)
if rel, err := filepath.Rel(base, cleanKey); err != err || strings.HasPrefix(rel, "..") {
return c.Status(http.StatusBadRequest).JSON(fiber.Map{"error": "path traversal detected"})
}
// Store metadata in DynamoDB using the validated key as a partition key
_, dErr := client.PutItem(c.Context(), &dynamodb.PutItemInput{
TableName: aws.String("Attachments"),
Item: map[string]types.AttributeValue{
"Key": &types.AttributeValueMemberS{Value: body.Key},
"Owner": &types.AttributeValueMemberS{Value: c.IP()}, // example attribute
},
})
if dErr != nil {
return c.Status(http.StatusInternalServerError).JSON(fiber.Map{"error": "failed to store metadata"})
}
// Safe filesystem write using the cleaned relative path
finalPath := filepath.Join(base, rel)
if err := c.SaveFile(c.FormFile("file"), finalPath); err != nil {
return c.Status(http.StatusInternalServerError).JSON(fiber.Map{"error": "unable to save file"})
}
return c.JSON(fiber.Map{"message": "uploaded"})
})
app.Listen(":3000")
}
func isValidKey(key string) bool {
// Allow letters, digits, underscore, hyphen, dot, and slashes for directory-like keys
// but ensure no null bytes or shell metacharacters
for _, r := range key {
if !(r == '/' || r == '.' || r == '-' || r == '_' || (r >= 'a' && r <= 'z') || (r >= '0' && r <= '9') || (r >= 'A' && r <= 'Z')) {
return false
}
}
return key != "" && !strings.Contains(key, "..")
}
This approach ensures that any key used with DynamoDB is validated before being stored or used in filesystem paths, effectively mitigating Zip Slip in the Fiber + DynamoDB context.