Shellshock in Chi
How Shellshock Manifests in Chi
Shellshock vulnerabilities in Chi applications typically emerge through unsafe shell command execution patterns. Chi, being a Go-based HTTP router, doesn't directly execute shell commands, but vulnerabilities arise when handlers improperly invoke system processes.
The most common Shellshock manifestation occurs when Chi handlers construct shell commands using untrusted HTTP parameters. For example:
func unsafeHandler(w http.ResponseWriter, r *http.Request) {
cmd := exec.Command("sh", "-c", r.URL.Query().Get("command"))
output, _ := cmd.CombinedOutput()
w.Write(output)
}
This pattern is particularly dangerous because Chi's parameter parsing makes it trivial to inject malicious payloads. An attacker could exploit this by sending:
GET /unsafe?command=echo+hello;+bash+-c+%22%24(%2fbin%2febay+-r+%27%20%27)%22 HTTP/1.1
Chi's middleware chain often processes these requests before reaching the vulnerable handler, but the core issue remains: unsanitized input flows directly into shell contexts.
Another Chi-specific pattern involves using environment variables for configuration that later get passed to shell commands. Consider this middleware setup:
func authMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
token := r.Header.Get("Authorization")
os.Setenv("API_TOKEN", token)
next.ServeHTTP(w, r)
})
}
func execHandler(w http.ResponseWriter, r *http.Request) {
cmd := exec.Command("sh", "-c", "curl -H 'Authorization: $API_TOKEN' https://api.example.com/data")
output, _ := cmd.CombinedOutput()
w.Write(output)
}
Here, Chi's middleware makes it easy to establish an environment where user-controlled data becomes part of shell execution contexts.
Chi-Specific Detection
Detecting Shellshock vulnerabilities in Chi applications requires examining both code patterns and runtime behavior. Static analysis should focus on these specific Chi patterns:
grep -r 'exec\.Command.*sh.*-c' . --include='*.go'
grep -r 'os\.Setenv' . --include='*.go' | grep -A5 -B5 'exec'
grep -r 'fmt\.Sprintf.*sh' . --include='*.go'
Dynamic scanning with middleBrick reveals Shellshock vulnerabilities by actively testing for command injection through Chi endpoints. The scanner sends payloads designed to trigger shell interpretation:
GET /chi-endpoint?param=$(sleep+10) HTTP/1.1
GET /chi-endpoint?param=%28%29%7b%3b%7d HTTP/1.1
middleBrick's black-box approach is particularly effective because it doesn't require source code access. It tests the actual runtime behavior of Chi applications, sending carefully crafted payloads to each endpoint and analyzing responses for signs of command execution.
For Chi applications using middleware chains, middleBrick traces the complete request flow:
chi.Router{
middleware1,
middleware2,
vulnerableHandler,
}
The scanner identifies where user input enters the system and whether it reaches dangerous execution contexts, even when wrapped in multiple middleware layers.
Runtime monitoring can also detect Shellshock exploitation attempts. Look for unusual process creation patterns:
strace -f -p <pid> 2>&1 | grep -E '(execve|fork|clone)'
Chi applications should show predictable process behavior—unexpected shell process creation indicates potential exploitation.
Chi-Specific Remediation
Remediating Shellshock vulnerabilities in Chi applications requires eliminating shell command execution entirely or implementing strict input validation. The most effective approach is avoiding shell invocation:
// BAD - vulnerable to Shellshock
func badHandler(w http.ResponseWriter, r *http.Request) {
cmd := exec.Command("sh", "-c", r.URL.Query().Get("script"))
output, _ := cmd.CombinedOutput()
w.Write(output)
}
// GOOD - safe alternative
func goodHandler(w http.ResponseWriter, r *http.Request) {
args := r.URL.Query().Get("script")
cmd := exec.Command("python3", "-c", args)
output, _ := cmd.CombinedOutput()
w.Write(output)
}
When shell execution is unavoidable, use argument arrays instead of shell strings:
func safeHandler(w http.ResponseWriter, r *http.Request) {
param := r.URL.Query().Get("param")
// Whitelist allowed characters
if matched, _ := regexp.MatchString(`^[a-zA-Z0-9_-]+$`, param); !matched {
http.Error(w, "Invalid input", http.StatusBadRequest)
return
}
cmd := exec.Command("sh", "-c", fmt.Sprintf("echo '%s'", param))
output, _ := cmd.CombinedOutput()
w.Write(output)
}
Chi's middleware architecture enables centralized security controls. Implement a validation middleware:
func shellshockProtection(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// Check for suspicious patterns
if strings.Contains(r.URL.RawQuery, "$(") || strings.Contains(r.URL.RawQuery, ";") {
http.Error(w, "Potential command injection detected", http.StatusBadRequest)
return
}
next.ServeHTTP(w, r)
})
}
// Apply to all routes
r := chi.NewRouter()
r.Use(shellshockProtection)
For applications that must execute dynamic commands, use a command builder pattern:
type CommandBuilder struct {
baseCommand string
args []string
}
func (cb *CommandBuilder) AddArg(arg string) error {
// Validate argument format
if matched, _ := regexp.MatchString(`^[a-zA-Z0-9./_-]+$`, arg); !matched {
return fmt.Errorf("invalid argument format")
}
cb.args = append(cb.args, arg)
return nil
}
func (cb *CommandBuilder) Build() *exec.Cmd {
return exec.Command(cb.baseCommand, cb.args...)
}
This approach ensures all shell interactions go through validated paths, eliminating Shellshock's injection vectors.