Path Traversal in Buffalo
How Path Traversal Manifests in Buffalo
Path traversal vulnerabilities in Buffalo applications typically emerge from how file operations handle user-supplied paths. The most common attack pattern involves manipulating file path parameters to access files outside the intended directory. For example, a Buffalo endpoint that serves static files might look like:
func ServeFile(c buffalo.Context) error {
filePath := c.Param("filename")
return c.File(filePath)
}
An attacker could request /api/files/../../etc/passwd to traverse outside the intended directory. Buffalo's default file serving uses Go's http.ServeFile which doesn't inherently prevent traversal, making this a critical vulnerability.
Another Buffalo-specific manifestation occurs with template rendering. If template paths are constructed dynamically from user input without validation:
func RenderTemplate(c buffalo.Context) error {
templateName := c.Param("template")
return c.Render(templateName, r.HTML(templateName))
}
An attacker could request /render?template=../../views/admin/secrets to access templates they shouldn't see.
Buffalo's asset pipeline can also be exploited. When serving bundled assets, if the path resolution isn't properly sanitized, attackers might access files outside the intended asset directories using sequences like ../ or URL-encoded equivalents like %2e%2e%2f.
Database file access is another vector. Buffalo applications using SQLite or similar databases might construct file paths for database connections from user input:
func ConnectDB(c buffalo.Context) error {
dbPath := c.Param("db")
db, err := sql.Open("sqlite3", dbPath)
// ...
}
An attacker could traverse to sensitive database files or configuration files containing credentials.
Buffalo-Specific Detection
Detecting path traversal in Buffalo requires both static analysis and runtime scanning. For static detection, look for these Buffalo-specific patterns:
Parameter-based file operations:
# Search for file operations using parameters
grep -r "c.Param(" . | grep -E "(File|ReadFile|Open|ServeFile)"
Template path construction:
# Find dynamic template rendering
grep -r "c.Render(" . | grep -v "r.HTML(" | grep -E "(Param|Query|Form)"
Asset path handling:
# Check asset serving implementations
grep -r "asset" . | grep -E "(Path|URL|Serve)"
For runtime scanning with middleBrick, the tool automatically tests for path traversal by sending encoded traversal sequences to file-serving endpoints. It checks for:
- Basic
../traversal sequences - URL-encoded variants like
%2e%2e%2f - Windows-style
..\sequences - Overlong UTF-8 encodings
- Null byte injections
middleBrick's scanner specifically targets Buffalo's common patterns by testing endpoints that accept file paths, template names, or asset identifiers. The scanner reports findings with the exact traversal sequence that succeeded, the file accessed, and the severity based on the sensitivity of the accessed file.
For comprehensive testing, middleBrick integrates with Buffalo's development server to scan running applications without requiring source code access. This black-box approach tests the actual attack surface as it exists in production.
Buffalo-Specific Remediation
Buffalo provides several native approaches to prevent path traversal. The most robust solution uses path normalization and validation before any file operation:
import (
"path/filepath"
"strings"
)
func SafeFilePath(baseDir, userPath string) (string, error) {
// Clean and normalize the path
cleanPath := filepath.Clean(userPath)
// Check for traversal attempts
if strings.Contains(cleanPath, "..") {
return "", errors.New("path traversal attempt detected")
}
// Resolve to absolute path and verify it's within base directory
targetPath := filepath.Join(baseDir, cleanPath)
targetAbs, err := filepath.Abs(targetPath)
if err != nil {
return "", err
}
baseAbs, err := filepath.Abs(baseDir)
if err != nil {
return "", err
}
// Ensure the resolved path is within the base directory
if !strings.HasPrefix(targetAbs, baseAbs+string(filepath.Separator)) {
return "", errors.New("path traversal: resolved path outside base directory")
}
return targetAbs, nil
}
// Usage in a Buffalo handler
func ServeFile(c buffalo.Context) error {
userPath := c.Param("filename")
safePath, err := SafeFilePath("/var/app/files", userPath)
if err != nil {
return c.Error(http.StatusBadRequest, err)
}
return c.File(safePath)
}
For template rendering, Buffalo's template engine can be configured with a whitelist approach:
var allowedTemplates = map[string]bool{
"home.html": true,
"profile.html": true,
"dashboard.html": true,
}
func RenderTemplate(c buffalo.Context) error {
templateName := c.Param("template")
if !allowedTemplates[templateName] {
return c.Error(http.StatusNotFound, errors.New("template not allowed"))
}
return c.Render(templateName, r.HTML(templateName))
}
Buffalo's asset handling can be secured using the built-in asset pipeline with proper path validation:
func ServeAsset(c buffalo.Context) error {
assetName := c.Param("asset")
// Use Buffalo's asset helper which validates paths
assetPath, err := assets.Path(assetName)
if err != nil {
return c.Error(http.StatusNotFound, err)
}
return c.File(assetPath)
}
For database file access, validate and sanitize paths before connection:
func ConnectDB(c buffalo.Context) error {
dbPath := c.Param("db")
// Only allow specific database directories
allowedDirs := []string{"/var/app/db", "/tmp"}
safePath, err := SafeFilePath("/var/app/db", dbPath)
if err != nil {
return c.Error(http.StatusBadRequest, err)
}
db, err := sql.Open("sqlite3", safePath)
if err != nil {
return err
}
// Store db in context for use
c.Set("db", db)
return nil
}
For comprehensive protection, implement a middleware that validates all file paths before they reach handlers:
func PathTraversalMiddleware(next buffalo.Handler) buffalo.Handler {
return func(c buffalo.Context) error {
// Check for suspicious patterns in all parameters
for _, v := range c.Params() {
if str, ok := v.(string); ok {
if strings.Contains(str, "..") || strings.Contains(str, "%2e") {
return c.Error(http.StatusBadRequest, errors.New("suspicious path detected"))
}
}
}
return next(c)
}
}
// Use in app setup
app.Use(PathTraversalMiddleware)
Related CWEs: inputValidation
| CWE ID | Name | Severity |
|---|---|---|
| CWE-20 | Improper Input Validation | HIGH |
| CWE-22 | Path Traversal | HIGH |
| CWE-74 | Injection | CRITICAL |
| CWE-77 | Command Injection | CRITICAL |
| CWE-78 | OS Command Injection | CRITICAL |
| CWE-79 | Cross-site Scripting (XSS) | HIGH |
| CWE-89 | SQL Injection | CRITICAL |
| CWE-90 | LDAP Injection | HIGH |
| CWE-91 | XML Injection | HIGH |
| CWE-94 | Code Injection | CRITICAL |