Zip Slip in Gin with Dynamodb
Zip Slip in Gin 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 Gin-based service that interacts with Amazon DynamoDB, this typically manifests when filenames or key names extracted from request parameters are used directly to build S3 object keys, local file paths, or DynamoDB item attributes that later influence storage or retrieval operations.
Consider a handler that accepts a file name from a client and stores metadata in DynamoDB. If the handler uses the raw user input to define a key or path, an attacker can supply a specially crafted value such as ../../../etc/passwd. When this value is concatenated with a base directory or used as part of a DynamoDB attribute that influences file storage, it can traverse directory boundaries and overwrite arbitrary files on the host filesystem where the application runs. Even if the immediate DynamoDB write does not directly expose filesystem content, the poisoned key can affect later stages of data handling, such as logging, export processes, or downstream integrations that read from DynamoDB and materialize files locally.
The vulnerability is amplified when the application uses DynamoDB Streams or event-driven triggers. A malicious key written to a DynamoDB table can propagate to downstream consumers that resolve paths dynamically, leading to unauthorized file access or inclusion. Because Gin does not inherently sanitize path segments, developers must explicitly validate and sanitize any user input that contributes to file system paths or object keys derived from DynamoDB attributes.
An example attack chain involves an attacker sending a POST request with a filename parameter set to ../../malicious.txt. The Gin handler writes metadata to DynamoDB, including the filename as an attribute. Later, a background worker reads the attribute and constructs a local path, inadvertently allowing file overwrite or disclosure. MiddleBrick scans detect such risky input flows and highlight them in the input validation and property authorization checks.
Dynamodb-Specific Remediation in Gin — concrete code fixes
To remediate Zip Slip in Gin when using DynamoDB, enforce strict input validation and path sanitization before using any user-controlled data in file or key construction. Use a allowlist of permitted characters for filenames and reject any input containing path traversal sequences or null bytes.
Below is a secure Gin handler example that validates and sanitizes filenames before storing metadata in DynamoDB using the AWS SDK for Go. The code ensures that filenames are clean and do not contain traversal patterns.
//go:generate mockgen -source=handler.go -destination=mock_handler.go
package main
import (
"context"
"net/http"
"path/filepath"
"regexp"
"strings"
"github.com/gin-gonic/gin"
"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"
)
var safeFilename = regexp.MustCompile(`^[a-zA-Z0-9_.-]+$`)
func sanitizeFilename(name string) (string, bool) {
// Remove any leading/trailing dots and whitespace
name = strings.TrimSpace(name)
name = strings.Trim(name, ".")
// Ensure no path separators or dangerous characters
if strings.ContainsAny(name, `\/:`) || !safeFilename.MatchString(name) {
return "", false
}
// Use Clean to eliminate any remaining traversal attempts
return filepath.Clean(name), true
}
func uploadHandler(client *dynamodb.Client) gin.HandlerFunc {
return func(c *gin.Context) {
filename := c.Query("filename")
cleanName, ok := sanitizeFilename(filename)
if !ok {
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid filename"})
return
}
// Prepare DynamoDB item with sanitized filename
item := map[string]types.AttributeValue{
"id": &types.AttributeValueMemberS{Value: cleanName},
"owner": &types.AttributeValueMemberS{Value: c.Query("owner")},
}
_, err := client.PutItem(context.Background(), &dynamodb.PutItemInput{
TableName: aws.String("SecureFiles"),
Item: item,
})
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusOK, gin.H{"status": "ok", "filename": cleanName})
}
}
func main() {
cfg, err := config.LoadDefaultConfig(context.Background())
if err != nil {
panic("unable to load SDK config")
}
client := dynamodb.NewFromConfig(cfg)
r := gin.Default()
r.GET("/upload", uploadHandler(client))
r.Run() // listen and serve on 0.0.0.0:8080
}
In this example, sanitizeFilename rejects paths and ensures only alphanumeric characters plus a limited set of safe symbols are allowed. The filename is further cleaned with filepath.Clean to remove any residual traversal attempts. By validating early and using the sanitized value for DynamoDB operations, you eliminate the risk of Zip Slip through filename-based paths.
Additionally, apply the same validation to any attributes that influence file system operations downstream, such as those processed by workers reading from DynamoDB. Combine this with middleware that normalizes paths and checks against a configured base directory for defense in depth. The middleBrick CLI can be used in CI/CD to enforce that handlers include proper input validation, and the dashboard can track regressions over time.
Frequently Asked Questions
How can I test my Gin endpoints for Zip Slip using middleBrick?
middlebrick scan https://your-api.example.com/upload. The scan will include input validation checks and highlight paths where user-controlled data flows into file or key construction without sanitization.