Command Injection in Fiber
How Command Injection Manifests in Fiber
Command injection vulnerabilities in Fiber applications typically arise when user input is incorporated into system commands without proper sanitization. Fiber's Go-based architecture means these vulnerabilities often appear in handler functions that execute external processes or shell commands based on HTTP request parameters.
A common pattern involves using os/exec with exec.Command where user input is concatenated into command strings. For example:
func getFileHandler(c *fiber.Ctx) error {
filename := c.Query("file")
cmd := exec.Command("cat", filename)
output, err := cmd.Output()
if err != nil {
return c.Status(500).SendString(err.Error())
}
return c.SendString(string(output))
}
This code is vulnerable because an attacker can supply a filename like file.txt; rm -rf /, causing the shell to execute multiple commands. The vulnerability becomes more severe when combined with Fiber's middleware ecosystem, where request parameters might flow through multiple processing layers before reaching command execution logic.
Another Fiber-specific scenario involves using user input in exec.CommandContext with shell expansion. Consider this handler:
func searchHandler(c *fiber.Ctx) error {
query := c.Query("q")
cmd := exec.Command("grep", "-r", query, "/var/www")
output, err := cmd.Output()
if err != nil {
return c.Status(500).SendString(err.Error())
}
return c.SendString(string(output))
}
While this appears safe, if query contains special characters like $(whoami) or backticks, they can be interpreted by the shell in certain execution contexts, especially if the command is later modified or if the Go runtime's command execution behavior changes.
Property authorization bypasses in Fiber can also lead to command injection when user input controls file paths or command arguments. A vulnerable pattern might look like:
func adminAction(c *fiber.Ctx) error {
action := c.Query("action")
if action == "backup" {
cmd := exec.Command("tar", "-czf", "/backups/"+c.Query("filename"), "/var/www")
return cmd.Run()
}
return c.Status(400).SendString("Invalid action")
}
Here, an attacker could manipulate the filename parameter to include directory traversal or command injection payloads, potentially overwriting critical files or executing arbitrary commands.
Fiber-Specific Detection
Detecting command injection in Fiber applications requires both static code analysis and dynamic runtime testing. middleBrick's black-box scanning approach is particularly effective for Fiber APIs because it tests the actual runtime behavior without requiring source code access.
middleBrick scans Fiber applications by sending crafted payloads to endpoints that might execute system commands. For command injection detection, it tests parameters with payloads like:
; echo 'injection'
$(whoami)
`id`
& cat /etc/passwd
| ls -la
The scanner analyzes responses for indicators of successful injection, such as unexpected output, timing differences, or error messages that reveal system information. middleBrick's 12 parallel security checks include specific tests for command injection patterns, examining both GET and POST parameters, headers, and even JSON payloads.
For Fiber applications using middleware chains, middleBrick's scanning simulates real-world attack scenarios where user input flows through multiple processing stages. This is crucial because command injection vulnerabilities might only manifest when certain middleware modifies or validates input in specific ways.
middleBrick's OpenAPI/Swagger analysis adds another layer of detection for Fiber apps. By analyzing the API specification alongside runtime scanning, it can identify endpoints that accept parameters likely to be used in command execution contexts. The scanner cross-references parameter definitions with actual runtime behavior to find mismatches between documented and implemented security controls.
LLM/AI security scanning is particularly relevant for Fiber applications using AI features. middleBrick tests for system prompt leakage and prompt injection that could lead to command execution through AI agents or tools. This includes testing for patterns like:
"system": "Execute: whoami",
"role": "user", "content": "run: ls -la"
middleBrick's scanning takes 5-15 seconds and provides a security score (0-100) with letter grades (A-F), making it easy to identify command injection vulnerabilities in Fiber applications during development or in production environments.
Fiber-Specific Remediation
Remediating command injection in Fiber applications requires a defense-in-depth approach using Go's native security features. The most fundamental fix is avoiding shell command execution entirely when possible. For file operations that might tempt developers to use shell commands, use Go's native file I/O instead:
func readFileHandler(c *fiber.Ctx) error {
filename := c.Query("file")
// Validate filename - allow only alphanumeric, hyphen, underscore, dot
if matched, _ := regexp.MatchString(`^[a-zA-Z0-9._-]+$`, filename); !matched {
return c.Status(400).SendString("Invalid filename")
}
// Use absolute path with safe directory
safeDir := "/var/www/files"
filePath := path.Join(safeDir, filename)
// Ensure path is within safeDir
if !strings.HasPrefix(filePath, safeDir) {
return c.Status(400).SendString("Invalid path")
}
data, err := os.ReadFile(filePath)
if err != nil {
return c.Status(404).SendString("File not found")
}
return c.Send(data)
}
When shell commands are unavoidable, use exec.Command with individual arguments instead of building command strings:
func safeCommand(c *fiber.Ctx) error {
cmdName := c.Query("cmd")
cmdArg := c.Query("arg")
// Whitelist allowed commands
allowedCommands := map[string]bool{
"ls": true,
"cat": true,
"grep": true,
}
if !allowedCommands[cmdName] {
return c.Status(400).SendString("Command not allowed")
}
// Validate arguments - allow only safe characters
if matched, _ := regexp.MatchString(`^[a-zA-Z0-9._/-]+$`, cmdArg); !matched {
return c.Status(400).SendString("Invalid argument")
}
cmd := exec.Command(cmdName, cmdArg)
output, err := cmd.Output()
if err != nil {
return c.Status(500).SendString(err.Error())
}
return c.SendString(string(output))
}
For Fiber applications with complex input validation needs, implement a validation middleware:
func validationMiddleware() fiber.Handler {
return func(c *fiber.Ctx) error {
// Check for suspicious patterns
suspiciousPatterns := []string{
"$(",
"`",
";",
"&",
"|",
"&&",
"||",
}
for _, pattern := range suspiciousPatterns {
if strings.Contains(c.OriginalURL(), pattern) {
return c.Status(400).SendString("Suspicious input detected")
}
}
return c.Next()
}
}
// Use in app setup
app := fiber.New()
app.Use(validationMiddleware())
Additionally, implement proper error handling to avoid information disclosure:
func executeWithTimeout(c *fiber.Ctx) error {
cmd := exec.Command("somecommand", c.Query("param"))
// Set timeout to prevent resource exhaustion
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
cmd = cmd.WithContext(ctx)
var output bytes.Buffer
cmd.Stdout = &output
cmd.Stderr = &output
err := cmd.Run()
if err != nil {
// Log error internally, don't expose system details
log.Printf("Command execution failed: %v", err)
return c.Status(500).SendString("Command execution failed")
}
return c.SendString(output.String())
}
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 |