Token Leakage in Gorilla Mux
How Token Leakage Manifests in Gorilla Mux
Token leakage in Gorilla Mux applications occurs when authentication tokens, API keys, or session identifiers are inadvertently exposed through HTTP responses, logs, or error messages. This vulnerability is particularly dangerous because attackers can harvest these tokens to impersonate legitimate users or escalate privileges.
In Gorilla Mux applications, token leakage often manifests through several specific patterns:
- 404 Error Responses: When a route doesn't match, Mux returns a 404 with the unmatched path in the response body, potentially exposing tokens in URLs
- Debug Error Pages: Development configurations may return stack traces containing headers or tokens
- Middleware Logging: Custom middleware that logs request details without filtering sensitive headers
- Redirect Loops: Improper redirect handling can expose tokens in Location headers
- Unprotected Static Assets: Serving files from directories containing configuration files with tokens
Consider this common Gorilla Mux pattern that leaks tokens:
package main
import (
"net/http"
"github.com/gorilla/mux"
)
func main() {
r := mux.NewRouter()
// Vulnerable: Logs full request including Authorization header
r.Use(loggingMiddleware)
r.HandleFunc("/api/data", protectedEndpoint).Methods("GET")
http.ListenAndServe(":8080", r)
}
func loggingMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// LEAKS: Logs Authorization header
log.Printf("Request: %s %s Headers: %+v", r.Method, r.URL, r.Header)
next.ServeHTTP(w, r)
})
}
func protectedEndpoint(w http.ResponseWriter, r *http.Request) {
token := r.Header.Get("Authorization")
// LEAKS: Returns token in response body if missing
if token == "" {
http.Error(w, "Missing Authorization: Bearer ", http.StatusUnauthorized)
}
// ... rest of endpoint
} This code leaks tokens through two mechanisms: the logging middleware exposes Authorization headers in logs, and the error response includes a template that could be populated with actual token values.
Gorilla Mux-Specific Detection
Detecting token leakage in Gorilla Mux applications requires both static analysis and runtime scanning. middleBrick's black-box scanner specifically tests for these vulnerabilities without requiring source code access.
For manual detection in Gorilla Mux applications, examine these areas:
- Middleware Chains: Review all middleware for logging sensitive data
- Error Handlers: Check custom error handlers for token exposure
- Route Definitions: Ensure no routes accidentally expose tokens in responses
- Static File Serving: Verify no sensitive files are accessible
middleBrick scans for token leakage by:
- Sending requests with various authentication headers and analyzing responses for token reflection
- Testing error conditions to see if tokens appear in error messages
- Checking response headers for token exposure
- Analyzing static asset responses for configuration files
Here's how to use middleBrick to scan a Gorilla Mux application:
# Install middleBrick CLI
npm install -g middlebrick
# Scan your API endpoint
scan_result=$(middlebrick scan https://your-api.com)
# Check the security score and findings
echo "$scan_result" | jq '.score .findings'The scanner will specifically flag issues like:
- Tokens appearing in 404 responses
- Debug information containing headers
- Stack traces with sensitive data
- Configuration files accessible via static serving
For development teams using Gorilla Mux, integrating middleBrick into your CI/CD pipeline ensures token leakage is caught before production deployment:
# .github/workflows/security.yml
name: Security Scan
on: [push, pull_request]
jobs:
security:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run middleBrick Scan
run: |
npm install -g middlebrick
middlebrick scan https://staging.your-api.com --fail-below B
continue-on-error: trueGorilla Mux-Specific Remediation
Remediating token leakage in Gorilla Mux applications involves implementing proper filtering and sanitization at multiple layers. Here are specific fixes using Gorilla Mux's native capabilities:
1. Secure Logging Middleware:
func secureLoggingMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// Create a copy of headers without sensitive information
safeHeaders := http.Header{}
for k, v := range r.Header {
if shouldFilterHeader(k) {
safeHeaders[k] = []string{"[REDACTED]"}
} else {
safeHeaders[k] = v
}
}
log.Printf("Request: %s %s Headers: %+v", r.Method, r.URL, safeHeaders)
next.ServeHTTP(w, r)
})
}
func shouldFilterHeader(header string) bool {
sensitive := []string{"authorization", "cookie", "x-api-key"}
for _, h := range sensitive {
if strings.ToLower(header) == h {
return true
}
}
return false
}2. Secure Error Handling:
func secureErrorHandler(w http.ResponseWriter, r *http.Request) {
// Custom 404 handler that doesn't expose tokens
r := mux.NewRouter()
r.NotFoundHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
http.Error(w, "Resource not found", http.StatusNotFound)
})
// Custom error pages without stack traces
r.Use(middleware.Recoverer())
}
// In production, configure Gorilla Mux to not show stack traces
r := mux.NewRouter()
// Disable detailed error messages
r.SetNotFoundHandler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
http.Error(w, "Not Found", http.StatusNotFound)
}))3. Static Asset Protection:
func secureFileServer() http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// Block access to sensitive files
if strings.HasSuffix(r.URL.Path, ".env") ||
strings.HasSuffix(r.URL.Path, ".key") ||
strings.HasSuffix(r.URL.Path, ".pem") {
http.Error(w, "Forbidden", http.StatusForbidden)
return
}
// Serve files from a safe directory
http.FileServer(http.Dir("./public")).ServeHTTP(w, r)
})
}
// Use in router
r := mux.NewRouter()
r.PathPrefix("/static/").Handler(secureFileServer())4. Token Validation Middleware:
func tokenValidationMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
token := r.Header.Get("Authorization")
if token == "" {
http.Error(w, "Unauthorized", http.StatusUnauthorized)
return
}
// Validate token format without logging it
if !isValidTokenFormat(token) {
http.Error(w, "Invalid token format", http.StatusBadRequest)
return
}
next.ServeHTTP(w, r)
})
}
func isValidTokenFormat(token string) bool {
// Check for Bearer prefix and valid JWT format
if !strings.HasPrefix(token, "Bearer ") {
return false
}
parts := strings.Split(token, " ")
if len(parts) != 2 {
return false
}
// Basic JWT format check (header.payload.signature)
jwtParts := strings.Split(parts[1], ".")
return len(jwtParts) == 3
}