Command Injection in Echo Go with Bearer Tokens
Command Injection in Echo Go with Bearer Tokens — how this specific combination creates or exposes the vulnerability
Command injection occurs when an attacker can inject and execute arbitrary system commands through an application. In an Echo Go API that accepts user input and passes it to shell commands—often while relying on Bearer tokens for authorization—this risk is elevated when input validation is weak or missing. Even when endpoints are protected by Bearer tokens, authorization does not imply sanitization: a token may prove identity and permissions, but it does not sanitize arguments passed to operating system utilities.
Consider an endpoint that pings a user-supplied host for diagnostics. If the handler builds a command by concatenating the token-derived user ID or an untrusted header into a shell command, an attacker who obtains a valid Bearer token (or guesses a token format) can exploit the injection path. For example, using backticks or exec.Command with improperly escaped arguments enables shell metacharacters like ;, &&, or | to alter command semantics. A token may grant access to the endpoint, but it does not prevent the handler from inadvertently invoking ping with attacker-controlled data, leading to arbitrary command execution on the host.
In the context of middleBrick’s security checks, this scenario maps to multiple concurrent checks: Authentication (valid Bearer token presence), Input Validation (unsafe use of user data in system commands), and BOLA/IDOR (if the token identifies a tenant or user and the command uses that identifier unsafely). An OpenAPI spec that defines a security scheme of type http with bearer format can make the endpoint appear authorized, while the runtime behavior remains vulnerable due to unsanitized arguments. Attack patterns like ping 127.0.0.1; id demonstrate how command injection can leak environment information or escalate impact, regardless of the token’s validity.
Real-world examples include handlers that use os/exec without argument escaping. If a developer writes cmd := exec.Command("ping", "-c", "1", host) where host comes directly from user input, an input like localhost; cat /etc/passwd can execute additional commands. Proper mitigation focuses on avoiding the shell entirely—using exec with explicit arguments—and validating and sanitizing all inputs, even when Bearer tokens control access.
Bearer Tokens-Specific Remediation in Echo Go — concrete code fixes
Remediation centers on strict input validation, avoiding shell invocation, and ensuring Bearer token usage is limited to authorization, not data concatenation. Below are concrete, safe patterns for Echo Go handlers.
Safe command execution without shell injection risk
Use exec.Command with explicit arguments and avoid the shell. Never pass user input as part of a command string that the shell would interpret.
// Safe: explicit arguments, no shell interpretation
package main
import (
"net/http"
"os/exec"
"github.com/labstack/echo/v4"
)
func pingHandler(c echo.Context) error {
// Bearer token is used for auth only; do not embed it in commands
host := c.QueryParam("host")
if host == "" {
return c.String(http.StatusBadRequest, "host parameter required")
}
// Validate host to allow only safe characters (alphanumeric, dots, dashes)
var allowed = regexp.MustCompile(`^[a-zA-Z0-9.\-]+$`)
if !allowed.MatchString(host) {
return c.String(http.StatusBadRequest, "invalid host value")
}
// Execute without shell: arguments are passed directly, no parsing
cmd := exec.Command("ping", "-c", "1", host)
out, err := cmd.Output()
if err != nil {
return c.String(http.StatusInternalServerError, "ping failed")
}
return c.String(http.StatusOK, string(out))
}
This approach ensures the Bearer token remains an authorization artifact and does not leak into command construction. Authorization checks can be performed via middleware that validates the token before reaching the handler.
Authorization middleware using Bearer tokens in Echo Go
Validate tokens early, keeping them out of command-building logic. Example middleware that extracts and validates a Bearer token without using it in system commands:
// Bearer token validation middleware
func AuthMiddleware(next echo.HandlerFunc) echo.HandlerFunc {
return func(c echo.Context) error {
auth := c.Request().Header.Get("Authorization")
const prefix = "Bearer "
if len(auth) < len(prefix) || auth[:len(prefix)] != prefix {
return c.String(http.StatusUnauthorized, "invalid authorization header")
}
token := auth[len(prefix):]
// Perform token validation (e.g., JWT verification, introspection)
if !isValidToken(token) {
return c.String(http.StatusForbidden, "invalid token")
}
// Attach user info to context for downstream use, not for command assembly
c.Set("user", extractUser(token))
return next(c)
}
}
func isValidToken(token string) bool {
// Implement actual validation (e.g., JWT parse and signature check)
return token == "expected_test_token"
}
With this pattern, the token is used solely for access control. Command construction relies on sanitized, explicit parameters, not on values derived from the token itself.
Input validation and safe data flows
Even with Bearer-based auth, ensure all user-controlled data is validated against strict allowlists. For hostnames or IPs, prefer netlookup-safe parsing instead of shell commands. If you must invoke system utilities, use Go’s standard library functions (e.g., net) rather than spawning shells.
| Risk | Insecure Pattern | Secure Pattern |
|---|---|---|
| Command injection via host parameter | exec.Command("sh", "-c", "ping -c 1 "+host) | exec.Command("ping", "-c", "1", host) with regex validation |
| Bearer token used in command args | cmd := exec.Command("curl", "-H", "Authorization: Bearer "+token) | Token validated in middleware; omitted from command args |
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 |