Injection Flaws in Chi
How Injection Flaws Manifest in Chi
Injection flaws in Chi applications typically occur when untrusted data is sent to an interpreter without proper validation or sanitization. Chi, being a lightweight HTTP router for Go, doesn't inherently prevent injection attacks—it focuses on routing and middleware management. The responsibility falls on developers to properly handle user input before it reaches vulnerable components.
Common injection vectors in Chi applications include:
- SQL Injection: When user input is directly concatenated into SQL queries
- Command Injection: When user data is passed to system commands without validation
- Template Injection: When user input is rendered in templates without escaping
- LDAP Injection: When user input is used in LDAP queries
- Cross-Site Scripting (XSS): When user input is reflected in HTTP responses without sanitization
Consider this vulnerable Chi middleware that processes user input:
func vulnerableHandler(w http.ResponseWriter, r *http.Request) {
name := r.URL.Query().Get("name")
query := fmt.Sprintf("SELECT * FROM users WHERE name = '%s'", name)
// Execute query directly - vulnerable to SQL injection
rows, _ := db.Query(query)
// ...
}An attacker could submit name=admin' OR '1'='1 to manipulate the SQL query. Chi's role is simply to route this request to the handler—it doesn't provide any injection protection.
Another common pattern in Chi applications is improper validation of path parameters:
router.Get("/users/{id}", func(w http.ResponseWriter, r *http.Request) {
id := chi.URLParam(r, "id")
// No validation - could be used for NoSQL injection or path traversal
result := getUserFromDB(id)
json.NewEncoder(w).Encode(result)
})Without proper validation, id could contain malicious payloads targeting the database layer.
Chi-Specific Detection
Detecting injection flaws in Chi applications requires a multi-layered approach. Since Chi itself doesn't provide security features, you need to implement detection at both the application and infrastructure levels.
Static Analysis: Use Go's built-in tools and linters to identify potentially vulnerable code patterns:
func analyzeCode() {
// Check for SQL string concatenation
// Look for fmt.Sprintf with SQL patterns
// Identify direct command execution with user input
}Dynamic Testing with middleBrick: The middleBrick scanner can detect injection vulnerabilities by sending malicious payloads to your Chi endpoints and analyzing responses. For example, it tests for SQL injection by injecting common payloads and checking if they alter query behavior.
Runtime Monitoring: Implement logging and monitoring to detect suspicious patterns:
func secureHandler(w http.ResponseWriter, r *http.Request) {
name := r.URL.Query().Get("name")
// Log suspicious patterns
if strings.Contains(name, "' OR '") || strings.Contains(name, "' UNION ") {
log.Warn().Str("input", name).Msg("Suspicious input detected")
}
// Validate input
if !isValidInput(name) {
http.Error(w, "Invalid input", http.StatusBadRequest)
return
}
// Use parameterized queries
stmt, _ := db.Prepare("SELECT * FROM users WHERE name = ?")
rows, _ := stmt.Query(name)
// ...
}middleBrick CLI Integration: Scan your Chi API endpoints directly from the terminal:
$ npm install -g middlebrick
$ middlebrick scan https://api.yourapp.com/users
This provides a security score and detailed findings, including any injection vulnerabilities detected through black-box testing.
Chi-Specific Remediation
Remediating injection flaws in Chi applications requires a defense-in-depth approach. Here are Chi-specific strategies:
1. Use Parameterized Queries: Always use prepared statements instead of string concatenation:
router.Get("/users/{id}", func(w http.ResponseWriter, r *http.Request) {
id := chi.URLParam(r, "id")
// Validate ID is numeric
if !isValidID(id) {
http.Error(w, "Invalid ID format", http.StatusBadRequest)
return
}
// Use parameterized query
stmt, err := db.Prepare("SELECT * FROM users WHERE id = ?")
if err != nil {
http.Error(w, "Database error", http.StatusInternalServerError)
return
}
defer stmt.Close()
rows, err := stmt.Query(id)
if err != nil {
http.Error(w, "Query failed", http.StatusInternalServerError)
return
}
var users []User
for rows.Next() {
var u User
err := rows.Scan(&u.ID, &u.Name, &u.Email)
if err != nil {
http.Error(w, "Scan error", http.StatusInternalServerError)
return
}
users = append(users, u)
}
json.NewEncoder(w).Encode(users)
})2. Input Validation Middleware: Create reusable validation middleware for Chi:
func validateInput(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// Check for suspicious patterns
if containsSQLInjection(r.URL.Query()) || containsXSS(r.FormValue("data")) {
http.Error(w, "Invalid input", http.StatusBadRequest)
return
}
next.ServeHTTP(w, r)
})
}
// Apply to router
router.Use(validateInput)3. Output Encoding: Always encode user data before rendering:
func renderUser(w http.ResponseWriter, r *http.Request) {
user := getUserFromDB(chi.URLParam(r, "id"))
// HTML encode output
tmpl, _ := template.New("user").Parse(`
<div>
<h1>{{.Name}}</h1>
<p>{{.Email}}</p>
</div>
`)
tmpl.Execute(w, user)
}4. Security Headers Middleware: Protect against XSS and other injection attacks:
func securityHeaders(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("X-Content-Type-Options", "nosniff")
w.Header().Set("X-Frame-Options", "DENY")
w.Header().Set("X-XSS-Protection", "1; mode=block")
w.Header().Set("Content-Security-Policy", "default-src 'self'")
next.ServeHTTP(w, r)
})
}
router.Use(securityHeaders)5. Regular Security Scanning: Integrate middleBrick into your CI/CD pipeline to catch injection flaws early:
# GitHub Actions workflow
name: Security Scan
on: [push, pull_request]
jobs:
security:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Run middleBrick scan
run: |
npm install -g middlebrick
middlebrick scan https://staging.yourapp.com --fail-below B