Command Injection in Echo Go with Basic Auth
Command Injection in Echo Go with Basic Auth — how this specific combination creates or exposes the vulnerability
Command Injection occurs when an attacker can cause an application to execute unintended system commands. In Go applications built with the Echo framework, this typically arises when user-controlled input is passed to OS-level commands without proper validation or escaping. The combination of Basic Authentication and command execution amplifies the risk because authentication state can influence which code paths are exercised during a scan, and because credentials may be echoed or logged in ways that expose sensitive context.
Consider an endpoint that accepts a filename query parameter and runs a system command to inspect the file. If the application uses Basic Auth to gate access, an authenticated user’s username or password may be available in request context. When that input is concatenated into a command string—such as using exec.Command with unsanitized parameters—an attacker can inject shell operators (e.g., &&, ||, ;) to run arbitrary commands. Even if the endpoint requires authentication, the scanner from middleBrick tests the unauthenticated attack surface where possible, and when authentication is required, findings may highlight how credentials could be leveraged to reach vulnerable handlers.
For example, the following Echo route is vulnerable because it passes user input directly to a shell command without sanitization:
package main
import (
"os/exec"
"github.com/labstack/echo/v4"
"net/http"
)
func main() {
e := echo.New()
e.GET('/inspect', func(c echo.Context) error {
filename := c.QueryParam("file")
cmd := exec.Command("sh", "-c", "cat /tmp/"+filename)
output, _ := cmd.Output()
return c.String(http.StatusOK, string(output))
})
e.Start(":8080")
}
An attacker could supply ?file=../../../etc/passwd;id to read sensitive files and execute id. If Basic Auth guards this route, a valid credential set obtained through phishing or reuse could allow an authenticated attacker to trigger the injection. middleBrick’s LLM/AI Security checks include active prompt injection probes and system prompt leakage detection, which are useful for APIs that integrate AI components, but for traditional command paths, the focus remains on input validation and separation of control and data.
Additionally, the scanner’s checks for Unsafe Consumption and Input Validation will flag instances where headers, cookies, or query parameters directly influence command construction. Because middleBrick runs 12 security checks in parallel, it can highlight whether authentication mechanisms inadvertently affect which endpoints are exercised during testing, and whether credentials are present in logs or error messages that could aid an attacker.
Basic Auth-Specific Remediation in Echo Go — concrete code fixes
Remediation centers on never passing unsanitized user input to shell commands and enforcing strict input validation. The safest approach is to avoid the shell entirely and use exec.Command with explicit arguments. Below is a hardened version of the previous example that eliminates shell injection by avoiding -c and passing arguments directly:
package main
import (
"os/exec"
"github.com/labstack/echo/v4"
"net/http"
"path/filepath"
"strings"
)
func main() {
e := echo.New()
e.GET('/inspect', func(c echo.Context) error {
filename := c.QueryParam("file")
// Validate filename: allow only alphanumeric, dash, underscore, and dot
if !isValidFilename(filename) {
return c.String(http.StatusBadRequest, "invalid filename")
}
base := "/tmp"
// Clean the path to prevent directory traversal
cleanPath := filepath.Clean(filepath.Join(base, filename))
// Ensure the resolved path stays within base
if !strings.HasPrefix(cleanPath, filepath.Clean(base)+string(filepath.Separator)) && cleanPath != filepath.Clean(base) {
return c.String(http.StatusBadRequest, "path traversal detected")
}
cmd := exec.Command("cat", cleanPath)
output, err := cmd.Output()
if err != nil {
return c.String(http.StatusInternalServerError, "command failed")
}
return c.String(http.StatusOK, string(output))
})
e.Start(":8080")
}
func isValidFilename(s string) bool {
for _, r := range s {
if !(('a' <= r && r <= 'z') || ('A' <= r && r <= 'Z') || ('0' <= r && r <= '9') || r == '-' || r == '_' || r == '.') {
return false
}
}
return s != "" && len(s) <= 255
}
For Basic Auth, ensure credentials are verified using secure methods and that the authentication middleware does not inadvertently expose credentials in logs. Here is a secure way to add Basic Auth to an Echo route without affecting command construction:
package main
import (
"github.com/labstack/echo/v4"
"github.com/labstack/echo/v4/middleware"
"net/http"
)
func basicAuthValidator(username, password string, c echo.Context) (bool, error) {
// Use a constant-time comparison in production and integrate with a secure store
return username == "admin" && password == "S3cureP@ss!", nil
}
func main() {
e := echo.New()
e.Use(middleware.BasicAuth(basicAuthValidator))
e.GET('/public', func(c echo.Context) error {
return c.String(http.StatusOK, "public endpoint")
})
e.GET('/inspect', func(c echo.Context) error {
// safe command execution as shown above
return nil
})
e.Start(":8080")
}
Using the middleBrick CLI (middlebrick scan <url>) or GitHub Action can help detect whether authentication gates are properly configured and whether any endpoints remain vulnerable despite credential requirements. The dashboard and MCP Server integrations further allow teams to track findings over time and embed checks into AI-assisted workflows.
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 |