Auth Bypass in Chi
How Auth Bypass Manifests in Chi
Auth bypass in Chi applications typically occurs through misconfigured middleware chains, improper route protection, and flawed authentication state management. The most common pattern involves skipping authentication middleware for routes that should be protected, allowing unauthenticated users to access sensitive endpoints.
Consider this vulnerable Chi setup:
router := chi.NewRouter()
// Vulnerable: Missing authentication on sensitive route
router.Get("/api/users/me", func(w http.ResponseWriter, r *http.Request) {
userID := r.Context().Value("userID").(string) // Panic if userID not set
user, err := db.GetUser(userID)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
json.NewEncoder(w).Encode(user)
})
// Protected route - but easily bypassed
router.Get("/api/admin", BasicAuth(Users),
func(w http.ResponseWriter, r *http.Request) {
// Admin logic here
})
The first route exposes user data without authentication middleware, while the second route's BasicAuth middleware can be bypassed if the middleware chain is improperly configured or if the middleware itself has flaws.
Another common Chi-specific auth bypass occurs with route mounting and sub-routers:
adminRouter := chi.NewRouter()
adminRouter.Use(BasicAuth(Admins))
// Mounting without proper context propagation
router.Mount("/admin", adminRouter)
router.Get("/admin/users/list", func(w http.ResponseWriter, r *http.Request) {
// This route bypasses the adminRouter middleware entirely!
json.NewEncoder(w).Encode(getAllUsers())
})
Here, mounting a sub-router doesn't automatically protect routes defined after the mount point. An attacker can directly access "/admin/users/list" without authentication.
Path parameter manipulation is another Chi-specific vulnerability:
router.Get("/api/users/{id}", func(w http.ResponseWriter, r *http.Request) {
id := chi.URLParam(r, "id")
user, err := db.GetUser(id)
// No authorization check - BOLA vulnerability
if err == nil {
json.NewEncoder(w).Encode(user)
return
}
http.Error(w, "Not found", http.StatusNotFound)
})
This allows authenticated users to access other users' data by simply changing the ID parameter - a classic Broken Object Level Authorization (BOLA) issue that manifests as auth bypass in practice.
Chi-Specific Detection
Detecting auth bypass in Chi applications requires both static analysis of the routing structure and dynamic testing of the authentication flow. Start by examining your router configuration for missing middleware:
func auditRouter(router *chi.Mux) []string {
var issues []string
router.Walk(func(method string, path string, handler http.Handler, middlewares ...func(http.Handler) http.Handler) error {
// Check if protected routes lack auth middleware
if strings.HasPrefix(path, "/api/admin") || strings.HasPrefix(path, "/api/users") {
hasAuth := false
for _, mw := range middlewares {
if strings.Contains(fmt.Sprintf("%T", mw), "BasicAuth") ||
strings.Contains(fmt.Sprintf("%T", mw), "JWT") {
hasAuth = true
break
}
}
if !hasAuth {
issues = append(issues, fmt.Sprintf("Missing auth on %s %s", method, path))
}
}
return nil
})
return issues
}
This audit function walks through all routes and identifies sensitive endpoints lacking authentication middleware.
For runtime detection, use middleBrick's black-box scanning to identify auth bypass vulnerabilities without needing source code access:
middlebrick scan https://api.example.com --tests auth-bypass,bola
middleBrick tests authentication by attempting to access protected endpoints without credentials, checking for successful unauthorized access, and analyzing response patterns that indicate missing authorization checks.
Another detection technique involves testing middleware chain integrity:
func TestAuthMiddlewareChain(t *testing.T) {
router := chi.NewRouter()
// Create test routes
router.Get("/test/protected", BasicAuth(Users), func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
})
// Test that auth is required
req := httptest.NewRequest("GET", "/test/protected", nil)
w := httptest.NewRecorder()
router.ServeHTTP(w, req)
if w.Code != http.StatusUnauthorized {
t.Errorf("Auth bypass detected: expected 401, got %d", w.Code)
}
}
This test verifies that authentication middleware is properly enforced and cannot be bypassed through routing misconfiguration.
Chi-Specific Remediation
Remediating auth bypass in Chi requires a defense-in-depth approach with proper middleware usage, route organization, and authorization checks. Start with a centralized authentication middleware:
type Claims struct {
UserID string `json:"user_id"`
Roles []string `json:"roles"`
jwt.RegisteredClaims
}
func JWTAuth(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
tokenHeader := r.Header.Get("Authorization")
if tokenHeader == "" {
http.Error(w, "Missing token", http.StatusUnauthorized)
return
}
token, err := jwt.ParseWithClaims(tokenHeader, &Claims{}, func(token *jwt.Token) (interface{}, error) {
return []byte(os.Getenv("JWT_SECRET")), nil
})
if err != nil || !token.Valid {
http.Error(w, "Invalid token", http.StatusUnauthorized)
return
}
claims := token.Claims.(*Claims)
ctx := context.WithValue(r.Context(), "user", claims)
next.ServeHTTP(w, r.WithContext(ctx))
})
}
Apply this middleware consistently across all protected routes:
router := chi.NewRouter()
// Protected API routes
apiRouter := chi.NewRouter()
apiRouter.Use(JWTAuth)
apiRouter.Get("/users/me", func(w http.ResponseWriter, r *http.Request) {
claims := r.Context().Value("user").(*Claims)
user, err := db.GetUser(claims.UserID)
if err != nil {
http.Error(w, "User not found", http.StatusNotFound)
return
}
json.NewEncoder(w).Encode(user)
})
apiRouter.Get("/users/{id}", func(w http.ResponseWriter, r *http.Request) {
claims := r.Context().Value("user").(*Claims)
id := chi.URLParam(r, "id")
// Authorization check - prevent BOLA
if claims.UserID != id && !contains(claims.Roles, "admin") {
http.Error(w, "Access denied", http.StatusForbidden)
return
}
user, err := db.GetUser(id)
if err != nil {
http.Error(w, "Not found", http.StatusNotFound)
return
}
json.NewEncoder(w).Encode(user)
})
router.Mount("/api", apiRouter)
For role-based access control in Chi, create a dedicated authorization middleware:
func RequireRole(role string) func(next http.Handler) http.Handler {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
claims := r.Context().Value("user").(*Claims)
if !contains(claims.Roles, role) {
http.Error(w, "Insufficient permissions", http.StatusForbidden)
return
}
next.ServeHTTP(w, r)
})
}
}
// Usage
adminRouter := chi.NewRouter()
adminRouter.Use(JWTAuth, RequireRole("admin"))
adminRouter.Get("/stats", func(w http.ResponseWriter, r *http.Request) {
json.NewEncoder(w).Encode(getAdminStats())
})
Always validate input parameters and enforce authorization checks even when authentication passes:
func validateOwnership(userID string, resourceOwnerID string, userRoles []string) bool {
if userID == resourceOwnerID {
return true
}
// Admin can access any resource
for _, role := range userRoles {
if role == "admin" {
return true
}
}
return false
}
Integrate middleBrick into your development workflow to catch auth bypass regressions:
# .github/workflows/security.yml
name: Security Scan
on: [push, pull_request]
jobs:
security:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Run middleBrick Scan
run: |
npm install -g middlebrick
middlebrick scan https://staging.example.com/api \
--tests auth-bypass,bola,rate-limiting \
--fail-below B
continue-on-error: true
This CI/CD integration ensures auth bypass vulnerabilities are caught before deployment, maintaining the security posture of your Chi applications.
Related CWEs: authentication
| CWE ID | Name | Severity |
|---|---|---|
| CWE-287 | Improper Authentication | CRITICAL |
| CWE-306 | Missing Authentication for Critical Function | CRITICAL |
| CWE-307 | Brute Force | HIGH |
| CWE-308 | Single-Factor Authentication | MEDIUM |
| CWE-309 | Use of Password System for Primary Authentication | MEDIUM |
| CWE-347 | Improper Verification of Cryptographic Signature | HIGH |
| CWE-384 | Session Fixation | HIGH |
| CWE-521 | Weak Password Requirements | MEDIUM |
| CWE-613 | Insufficient Session Expiration | MEDIUM |
| CWE-640 | Weak Password Recovery | HIGH |