Crlf Injection in Chi
How Crlf Injection Manifests in Chi
CRLF injection vulnerabilities in Chi applications occur when untrusted user input containing carriage return ( ) and line feed ( ) characters is incorporated into HTTP headers without proper sanitization. In Chi-based Go applications, this manifests through several common patterns that developers encounter when building middleware or handling request parameters.
The most frequent occurrence happens in custom header manipulation. Consider a Chi application that echoes back client information:
func echoHeader(w http.ResponseWriter, r *http.Request) {
userAgent := r.URL.Query().Get("ua")
w.Header().Set("X-Reflected-UA", userAgent)
w.WriteHeader(http.StatusOK)
}If an attacker sends ?ua=Firefox
Content-Length: 35
You've been pwned!, the response headers become:
HTTP/1.1 200 OK
X-Reflected-UA: Firefox
Content-Length: 35
You've been pwned!This demonstrates how CRLF characters split the header section from the body, allowing response splitting attacks.
Chi's middleware chain amplifies this risk. When building authentication or logging middleware that captures and reflects request data, developers often inadvertently create injection points:
func loggingMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// Vulnerable: directly using query parameters in headers
userID := r.URL.Query().Get("user_id")
w.Header().Set("X-User-ID", userID)
next.ServeHTTP(w, r)
})
}Another Chi-specific manifestation occurs with URL parameter handling. Chi's robust routing allows dynamic parameters that, if reflected in responses, create injection opportunities:
router.Get("/user/{id}/profile", func(w http.ResponseWriter, r *http.Request) {
id := chi.URLParam(r, "id")
// Vulnerable: id used in header without validation
w.Header().Set("X-User-ID", id)
// ... rest of handler
})The context injection pattern in Chi also presents risks. Developers commonly store user data in request context and later extract it for response headers:
func authMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// Store in context
ctx := context.WithValue(r.Context(), "user_role", r.URL.Query().Get("role"))
next.ServeHTTP(w, r.WithContext(ctx))
})
}
func profileHandler(w http.ResponseWriter, r *http.Request) {
role := r.Context().Value("user_role")
w.Header().Set("X-User-Role", role)
}Response splitting attacks become particularly dangerous when combined with Chi's middleware architecture, as multiple handlers might contribute to the final response, each potentially introducing CRLF characters.
Chi-Specific Detection
Detecting CRLF injection in Chi applications requires both manual code review and automated scanning. For manual detection, focus on these Chi-specific patterns:
Code Review Checklist:
- Search for
w.Header().Set()calls that use request parameters - Identify middleware that reflects request data in response headers
- Look for
chi.URLParam()usage in header construction - Check context values being used in response generation
- Review any custom response writers or header manipulators
- Examine error responses that might include user input
Automated Scanning with middleBrick:
middleBrick's black-box scanner specifically tests for CRLF injection by submitting payloads containing %0D%0A (URL-encoded CRLF) to various endpoints. The scanner tests:
GET /endpoint?param=Firefox%0D%0AContent-Length:%2035%0D%0A%0D%0AAttackData HTTP/1.1middleBrick analyzes the response to detect:
- Additional headers appearing in the response
- Body content appearing before the expected response body
- HTTP status code changes
- Content-Length header manipulation
The scanner provides Chi-specific context by mapping findings to the actual HTTP handlers that processed the request, showing the exact code path where the vulnerability exists.
Testing Individual Endpoints:
# Test a specific Chi endpoint
middlebrick scan https://api.example.com/user/123/profileThe CLI output includes severity levels and the specific header that was vulnerable to injection, along with remediation guidance tailored to Go/Chi patterns.
CI/CD Integration:
Adding middleBrick to your Chi application's CI/CD pipeline ensures CRLF injection vulnerabilities are caught before deployment:
name: API Security Scan
on: [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.example.com/api --fail-threshold CThis configuration fails the build if any endpoint receives a C grade or lower, preventing CRLF injection vulnerabilities from reaching production.
Chi-Specific Remediation
Remediating CRLF injection in Chi applications requires input validation and proper header construction. Here are Chi-specific fixes for common vulnerable patterns:
Input Validation Middleware:
func sanitizeHeaders(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// Sanitize all query parameters
r = sanitizeQueryParams(r)
// Sanitize context values
ctx := sanitizeContextValues(r.Context())
next.ServeHTTP(w, r.WithContext(ctx))
})
}
func sanitizeQueryParams(r *http.Request) *http.Request {
q := r.URL.Query()
for key := range q {
q[key] = sanitizeInput(q[key][0])
}
r.URL.RawQuery = q.Encode()
return r
}
func sanitizeInput(input string) string {
return strings.ReplaceAll(strings.ReplaceAll(input, "\r", ""), "\n", "")
}Safe Header Construction:
func safeHeaderSet(w http.ResponseWriter, key, value string) {
sanitizedValue := sanitizeInput(value)
w.Header().Set(key, sanitizedValue)
}
// Usage in handlers
func userProfile(w http.ResponseWriter, r *http.Request) {
id := chi.URLParam(r, "id")
safeHeaderSet(w, "X-User-ID", id)
// ... rest of handler
}Context Sanitization:
func safeContextValue(ctx context.Context, key string) string {
value := ctx.Value(key)
if value == nil {
return ""
}
return sanitizeInput(fmt.Sprintf("%v", value))
}
// In middleware
func authMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
role := r.URL.Query().Get("role")
sanitizedRole := sanitizeInput(role)
ctx := context.WithValue(r.Context(), "user_role", sanitizedRole)
next.ServeHTTP(w, r.WithContext(ctx))
})
}Comprehensive Input Validation:
func validateInput(input string) error {
if strings.ContainsAny(input, "\r\n") {
return fmt.Errorf("input contains forbidden characters")
}
// Additional validation rules
if len(input) > 100 {
return fmt.Errorf("input too long")
}
return nil
}
// Usage in handlers
func createUser(w http.ResponseWriter, r *http.Request) {
var user User
if err := json.NewDecoder(r.Body).Decode(&user); err != nil {
http.Error(w, "Invalid request", http.StatusBadRequest)
return
}
if err := validateInput(user.Name); err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
// Proceed with safe data
}Testing Remediation:
func TestCRLFInjection(t *testing.T) {
// Test that sanitization works
input := "Firefox\r\nContent-Length: 35\r\n\r\nAttack"
expected := "FirefoxContent-Length: 35Attack"
if sanitizeInput(input) != expected {
t.Errorf("Sanitization failed")
}
// Test handler with injection attempt
req := httptest.NewRequest("GET", "/user/123/profile?role=admin%0D%0AX-Injected:Value", nil)
w := httptest.NewRecorder()
router := chi.NewRouter()
router.Use(sanitizeHeaders)
router.Get("/user/{id}/profile", userProfile)
router.ServeHTTP(w, req)
// Verify injected header not present
if w.Header().Get("X-Injected") != "" {
t.Errorf("CRLF injection succeeded")
}
}These remediation patterns ensure that CRLF injection vulnerabilities are eliminated throughout your Chi application's request processing pipeline.
Frequently Asked Questions
How does CRLF injection differ in Chi vs other Go frameworks?
chi.URLParam() function and context value system require specific sanitization patterns that aren't needed in frameworks with simpler routing.Can middleBrick detect CRLF injection in Chi applications running on localhost?
http://localhost:3000/api or any local development URL. The scanner works by making HTTP requests to the target endpoint, so as long as the Chi application is running and accessible from the scanning environment, middleBrick can test for CRLF injection vulnerabilities. This is particularly useful for testing before deployment to staging or production environments.