HIGH denial of servicechi

Denial Of Service in Chi

How Denial Of Service Manifests in Chi

Denial of Service (DoS) attacks in Chi applications typically exploit the framework's async nature and resource management patterns. Chi's lightweight middleware stack and router design create specific attack vectors that attackers can leverage to exhaust system resources.

The most common DoS pattern in Chi applications involves recursive middleware execution. Since Chi middleware chains are executed sequentially, an attacker can craft requests that trigger infinite loops through conditional middleware that never resolves. For example, a middleware that checks authentication tokens but fails to properly handle malformed tokens can cause repeated execution attempts.

func vulnerableMiddleware(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        // Missing token validation
        if r.Header.Get("Authorization") == "" {
            // No error response, just continues
        }
        next.ServeHTTP(w, r)
    })
}

Another Chi-specific DoS vector targets the context cancellation patterns. Chi uses Go's context package for request-scoped values and cancellation signals. Attackers can exploit poorly implemented context handling to create goroutine leaks. When a request handler spawns background goroutines without proper context cancellation, these goroutines continue running even after the client disconnects, gradually consuming memory and CPU.

func leakyHandler(w http.ResponseWriter, r *http.Request) {
    // Background goroutine without context cancellation
    go func() {
        for {
            // Infinite loop, never checks context
            time.Sleep(1 * time.Second)
            log.Println("Background task running")
        }
    }()
    w.Write([]byte("Processing"))
}

Chi's route matching algorithm also presents DoS opportunities. The framework uses a radix tree for efficient route matching, but complex route patterns with many parameters can cause excessive CPU usage during matching. Attackers can craft URLs with deeply nested parameters or unusual encoding that forces the router to perform expensive matching operations.

Resource exhaustion through file upload handling is another critical Chi DoS vector. Since Chi doesn't impose default limits on request bodies, attackers can upload extremely large files to exhaust disk space or memory. Without proper size limits and streaming processing, a single request can consume all available resources.

func unsafeUploadHandler(w http.ResponseWriter, r *http.Request) {
    file, _, err := r.FormFile("file")
    if err != nil {
        http.Error(w, err.Error(), http.StatusBadRequest)
        return
    }
    defer file.Close()
    
    // Reads entire file into memory without limits
    data, err := ioutil.ReadAll(file)
    if err != nil {
        http.Error(w, err.Error(), http.StatusInternalServerError)
        return
    }
    
    // Process data without size validation
    processData(data)
    w.Write([]byte("Upload complete"))
}

Chi-Specific Detection

Detecting DoS vulnerabilities in Chi applications requires understanding the framework's execution model and common failure patterns. The first step is runtime monitoring of request processing patterns and resource consumption.

Middleware-based monitoring provides the most effective detection approach for Chi applications. By instrumenting the middleware chain, you can track request execution time, memory allocation, and goroutine counts per request. This allows identification of requests that consume excessive resources or take abnormally long to process.

func monitoringMiddleware(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        start := time.Now()
        ctx := context.WithValue(r.Context(), "start_time", start)
        
        // Capture initial goroutine count
        initialGoroutines := runtime.NumGoroutine()
        
        next.ServeHTTP(w, r.WithContext(ctx))
        
        // Calculate metrics
        duration := time.Since(start)
        currentGoroutines := runtime.NumGoroutine()
        goroutineDelta := currentGoroutines - initialGoroutines
        
        log.Printf("Request: %s %s - Duration: %v - Goroutines: %d", 
            r.Method, r.URL.Path, duration, goroutineDelta)
        
        // Alert on suspicious patterns
        if duration > 5*time.Second || goroutineDelta > 10 {
            log.Printf("Suspicious request detected: %v", r.URL)
        }
    })
}

Static analysis of Chi route definitions can reveal potential DoS vulnerabilities. Tools that analyze Go source code can identify patterns like unbounded request body reading, missing context cancellation, and recursive middleware calls. Look for middleware chains that don't properly handle error conditions or have circular dependencies.

Automated scanning with middleBrick provides comprehensive DoS vulnerability detection for Chi applications. The scanner analyzes both the running application and OpenAPI specifications to identify security weaknesses. For Chi specifically, middleBrick tests for:

  • Missing rate limiting on endpoints
  • Unbounded request body sizes
  • Slowloris-style partial request attacks
  • Recursive middleware execution paths
  • Context cancellation bypass opportunities

middleBrick's black-box scanning approach is particularly effective for Chi applications since it tests the actual running API without requiring source code access. The scanner sends crafted requests designed to trigger DoS conditions and monitors the application's response patterns.

Performance profiling during normal operation establishes baseline metrics for comparison. Monitor CPU usage, memory allocation, and goroutine counts during typical load patterns. Sudden deviations from these baselines often indicate DoS attacks in progress.

Chi-Specific Remediation

Remediating DoS vulnerabilities in Chi applications requires a multi-layered approach that addresses both the framework's specific characteristics and general DoS prevention strategies. The most effective remediation combines rate limiting, request validation, and resource management.

Implementing rate limiting at the Chi router level provides the first line of defense. Chi's middleware architecture makes it easy to add rate limiting that applies to all routes. The key is choosing appropriate rate limits based on your application's capacity and user patterns.

func rateLimitMiddleware(next http.Handler) http.Handler {
    limiter := tollbooth.NewLimiter(10, time.Minute)
    limiter.SetMessage("Rate limit exceeded")
    limiter.SetStatusCode(http.StatusTooManyRequests)
    
    return tollbooth.LimitHandler(limiter, next)
}

// Apply to all routes
r := chi.NewRouter()
r.Use(rateLimitMiddleware)
r.Get("/api/users", getUsersHandler)
r.Post("/api/users", createUserHandler)

Request size limiting is critical for preventing resource exhaustion attacks. Chi doesn't impose default limits, so you must explicitly configure maximum request sizes for different content types. This prevents attackers from uploading massive files or sending oversized JSON payloads.

func sizeLimitMiddleware(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        // Set maximum request body size (10MB)
        r.Body = http.MaxBytesReader(w, r.Body, 10*1024*1024)
        
        // Check content type and apply specific limits
        contentType := r.Header.Get("Content-Type")
        switch {
        case strings.HasPrefix(contentType, "application/json"):
            r.Body = http.MaxBytesReader(w, r.Body, 2*1024*1024) // 2MB for JSON
        case strings.HasPrefix(contentType, "multipart/form-data"):
            r.Body = http.MaxBytesReader(w, r.Body, 50*1024*1024) // 50MB for uploads
        }
        
        next.ServeHTTP(w, r)
    })
}

Context cancellation patterns must be properly implemented to prevent goroutine leaks. Every background goroutine spawned by a request handler should respect the request context and terminate when the client disconnects or the timeout expires.

func safeHandler(w http.ResponseWriter, r *http.Request) {
    // Set a reasonable timeout for the request
    ctx, cancel := context.WithTimeout(r.Context(), 30*time.Second)
    defer cancel()
    
    // Background goroutine with context cancellation
    go func(ctx context.Context) {
        for {
            select {
            case <-ctx.Done():
                log.Println("Background task cancelled")
                return
            default:
                // Do work
                time.Sleep(1 * time.Second)
            }
        }
    }(ctx)
    
    // Main request processing
    select {
    case <-ctx.Done():
        http.Error(w, "Request timeout", http.StatusGatewayTimeout)
    default:
        w.Write([]byte("Request processed successfully"))
    }
}

Middleware execution safety requires careful design to prevent infinite loops and recursive calls. Each middleware should have clear exit conditions and proper error handling. Use middleware composition patterns that guarantee termination.

func safeMiddleware(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        // Check for recursive call prevention
        if r.Context().Value("middleware_depth") != nil {
            http.Error(w, "Recursive middleware detected", http.StatusInternalServerError)
            return
        }
        
        // Set middleware depth for this call
        ctx := context.WithValue(r.Context(), "middleware_depth", true)
        
        // Call next with timeout
        next.ServeHTTP(w, r.WithContext(ctx))
    })
}

Connection pooling and timeout configuration at the server level prevents resource exhaustion. Configure appropriate timeouts for read, write, and idle connections to ensure that stalled connections don't consume resources indefinitely.

server := &http.Server{
    Addr:         ":8080",
    Handler:      r,
    ReadTimeout:  10 * time.Second,
    WriteTimeout: 30 * time.Second,
    IdleTimeout:  60 * time.Second,
    MaxHeaderBytes: 1 << 20, // 1MB
}

Monitoring and alerting systems should track key metrics like request duration, memory usage, and goroutine counts. Set up alerts for abnormal patterns that might indicate DoS attacks in progress.

Related CWEs: resourceConsumption

CWE IDNameSeverity
CWE-400Uncontrolled Resource Consumption HIGH
CWE-770Allocation of Resources Without Limits MEDIUM
CWE-799Improper Control of Interaction Frequency MEDIUM
CWE-835Infinite Loop HIGH
CWE-1050Excessive Platform Resource Consumption MEDIUM

Frequently Asked Questions

How does Chi's async nature make it vulnerable to DoS attacks?
Chi's use of Go's goroutines and context package creates DoS vectors through goroutine leaks and improper context cancellation. When handlers spawn background goroutines without context awareness, these continue running after client disconnection, consuming memory and CPU. Additionally, Chi's middleware chain can create recursive execution paths if not properly designed with exit conditions.
Can middleBrick detect DoS vulnerabilities in my Chi application?
Yes, middleBrick's black-box scanning approach is particularly effective for Chi applications. It tests running APIs without requiring source code access, sending crafted requests to trigger DoS conditions like rate limit bypass attempts, recursive middleware execution, and resource exhaustion scenarios. The scanner provides severity ratings and specific remediation guidance for identified vulnerabilities.