Timing Attack in Gorilla Mux
How Timing Attack Manifests in Gorilla Mux
Timing attacks in Gorilla Mux typically occur when path parameter extraction creates measurable timing differences between valid and invalid requests. The vulnerability manifests through several Gorilla Mux-specific code paths.
The core issue stems from how Gorilla Mux processes route matching. When a request hits a router with multiple registered routes, the router iterates through registered routes sequentially until finding a match. This creates timing variations based on:
- Route registration order (earlier routes match faster)
- Parameter extraction complexity (more parameters = more processing time)
- Regex pattern matching overhead
- Path validation logic
Consider this vulnerable pattern:
r := mux.NewRouter()
r.HandleFunc("/users/{id:[0-9]+}", handler).Methods("GET")
r.HandleFunc("/users/me", meHandler).Methods("GET")An attacker can exploit timing differences by measuring response times for various inputs. Valid numeric IDs matching the regex will process faster than invalid paths that require full iteration. The regex engine itself introduces timing variations based on input complexity.
Another common manifestation occurs with nested routers and middleware. When Gorilla Mux applies middleware chains, each middleware adds processing time, creating measurable differences between authenticated and unauthenticated paths:
api := r.PathPrefix("/api").Subrouter()
api.Use(authMiddleware)
api.HandleFunc("/users/{id}", getUser).Methods("GET")
r.HandleFunc("/public/{id}", getPublicUser).Methods("GET")The authentication middleware creates a timing gap that attackers can measure to determine whether a path exists, even without valid credentials.
Parameter validation timing is particularly problematic. When Gorilla Mux extracts parameters using regex patterns, the validation process takes longer for inputs that partially match versus those that completely fail:
r.HandleFunc("/files/{filename:[a-zA-Z0-9_-]+}", serveFile).Methods("GET")Inputs like "../../etc/passwd" trigger more extensive regex processing than valid filenames, creating detectable timing differences.
Route variable extraction itself is a timing vector. Gorilla Mux's parameter parsing involves string manipulation and memory allocation that varies with input length and complexity:
vars := mux.Vars(r)
userID := vars["id"]
// Processing time varies with userID complexityLonger or more complex parameter values increase processing time, allowing attackers to infer valid parameter formats through timing measurements.
Gorilla Mux-Specific Detection
Detecting timing attacks in Gorilla Mux requires both manual code review and automated scanning. The vulnerability appears in specific code patterns that middleBrick's scanner can identify.
Manual detection focuses on these Gorilla Mux-specific patterns:
// Vulnerable: Sequential route registration creates timing variations
r := mux.NewRouter()
r.HandleFunc("/api/v1/users/{id}", handler1)
r.HandleFunc("/api/v1/users/{id}/posts", handler2)
r.HandleFunc("/api/v1/users/{id}/posts/{postID}", handler3)The scanner identifies routes with similar prefixes where timing differences could leak information about valid endpoints.
middleBrick detects timing attack vulnerabilities through these specific checks:
- Route parameter complexity analysis - identifies regex patterns that could create timing variations
- Sequential route matching analysis - detects registration orders that enable timing attacks
- Middleware chain timing analysis - identifies authentication timing gaps
- Parameter validation pattern analysis - detects vulnerable input validation logic
The scanner tests endpoints with varying input patterns to measure response time consistency. For example, it sends requests with:
# Valid numeric ID (fast)
GET /users/12345
# Invalid ID (slow due to full iteration)
GET /users/abcde
# Partially matching ID (medium timing)
GET /users/123abcmiddleBrick's LLM security module also detects timing-related vulnerabilities in AI endpoints that use Gorilla Mux, testing for system prompt leakage through timing variations in different prompt formats.
Runtime detection can be implemented using middleware that logs timing statistics:
func timingMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
start := time.Now()
next.ServeHTTP(w, r)
duration := time.Since(start)
log.Printf("%s %s %v", r.Method, r.URL.Path, duration)
})
}
r.Use(timingMiddleware)
r.HandleFunc("/users/{id}", handler).Methods("GET")This middleware helps identify routes with inconsistent processing times during development and testing.
Gorilla Mux-Specific Remediation
Remediating timing attacks in Gorilla Mux requires both architectural changes and code-level fixes. The goal is to eliminate measurable timing differences between valid and invalid requests.
Route registration optimization is the first defense. Group similar routes together and use more specific patterns first:
r := mux.NewRouter()
// Most specific routes first
r.HandleFunc("/users/me", meHandler).Methods("GET")
r.HandleFunc("/users/{id:[0-9]+}", getUser).Methods("GET")
r.HandleFunc("/users/{id}", fallbackHandler).Methods("GET")This ordering ensures that specific routes match quickly, reducing timing variations.
Parameter validation should use constant-time comparison functions. Replace direct string comparisons with:
import "crypto/subtle"
func validateUserID(id string) bool {
// Constant-time comparison prevents timing attacks
return subtle.ConstantTimeCompare([]byte(id), []byte(expectedID)) == 1
}
r.HandleFunc("/users/{id}", func(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
userID := vars["id"]
if !validateUserID(userID) {
http.Error(w, "Invalid user", http.StatusNotFound)
return
}
// Constant processing time regardless of validity
processUserRequest(w, r, userID)
}).Methods("GET")Implement uniform response timing using middleware:
func uniformTimingMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
start := time.Now()
next.ServeHTTP(w, r)
duration := time.Since(start)
// Enforce minimum processing time
minDuration := 100 * time.Millisecond
if duration < minDuration {
time.Sleep(minDuration - duration)
}
})
}
r.Use(uniformTimingMiddleware)
r.HandleFunc("/users/{id}", handler).Methods("GET")Route parameter handling should avoid regex where possible. Use simple string matching with explicit validation:
r.HandleFunc("/users/{id}", func(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
id := vars["id"]
// Uniform processing regardless of input
if !isValidUserID(id) {
http.Error(w, "Not found", http.StatusNotFound)
return
}
// Always perform same operations
result := processUser(id)
json.NewEncoder(w).Encode(result)
}).Methods("GET")For API endpoints, implement consistent error responses:
func uniformErrorHandler(w http.ResponseWriter, r *http.Request, err error) {
// Always take same time to respond
time.Sleep(100 * time.Millisecond)
if err == nil {
w.WriteHeader(http.StatusOK)
} else {
w.WriteHeader(http.StatusNotFound)
}
json.NewEncoder(w).Encode(map[string]string{"status": "processed"})
}
r.HandleFunc("/users/{id}", func(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
id := vars["id"]
// Uniform processing
result, err := findUser(id)
uniformErrorHandler(w, r, err)
}).Methods("GET")middleBrick's GitHub Action can enforce these remediation patterns in CI/CD pipelines, failing builds that contain vulnerable Gorilla Mux route configurations.