Cross Site Request Forgery in Chi
How Cross Site Request Forgery Manifests in Chi
Cross Site Request Forgery (CSRF) in Chi manifests through its middleware-based request processing pipeline. Since Chi is a lightweight, idiomatic HTTP router for Go, CSRF vulnerabilities typically emerge when handlers process state-changing requests without proper anti-CSRF protection.
The most common Chi-specific CSRF pattern occurs in POST/PUT/DELETE endpoints that modify user data. Without CSRF tokens or same-site cookies, an attacker can craft a malicious page that submits requests to your Chi application using the victim's authenticated session. For example:
<form action="https://api.example.com/api/v1/users/update" method="POST" id="csrf-form" style="display:none;">
<input type="hidden" name="email" value="[email protected]">
<input type="hidden" name="password" value="pwned">
</form>
<script>document.getElementById('csrf-form').submit();</script>In Chi applications, this becomes particularly dangerous because Chi's middleware chain executes before reaching your handler logic. If no CSRF middleware is mounted, the request proceeds directly to your business logic, potentially modifying sensitive data like user profiles, payment information, or administrative settings.
Chi's design philosophy emphasizes explicit middleware composition, which means CSRF protection must be deliberately added to the middleware chain. A typical vulnerable Chi setup might look like:
r := chi.NewRouter()
r.Use(middleware.Logger)
r.Use(middleware.Recoverer)
// Missing CSRF middleware here!
r.Post("/api/v1/users/update", updateUserHandler)
r.Put("/api/v1/admin/settings", adminSettingsHandler)The absence of CSRF protection in this chain allows any authenticated user to be tricked into submitting malicious requests. Chi's flexibility with middleware ordering also creates risks—if CSRF middleware is mounted after authentication middleware but before your handlers, it might not have access to the session context needed to validate tokens.
Chi-Specific Detection
Detecting CSRF vulnerabilities in Chi applications requires examining both the middleware chain and handler implementations. middleBrick's black-box scanning approach is particularly effective for Chi APIs because it tests the unauthenticated attack surface without requiring source code access.
When scanning a Chi API endpoint, middleBrick tests for CSRF by attempting state-changing requests without valid anti-CSRF tokens. For a Chi application running at https://api.example.com, middleBrick would:
- Identify POST/PUT/DELETE endpoints through OPTIONS requests and response analysis
- Attempt requests without anti-CSRF tokens to see if they succeed
- Check for cookie-based session validation without additional CSRF protection
- Analyze response patterns for authentication bypass indicators
For Chi applications that use OpenAPI specifications, middleBrick can cross-reference the spec definitions with runtime findings. If your Chi API serves a Swagger/OpenAPI spec at /swagger.json, middleBrick resolves $ref references and identifies endpoints that should require CSRF protection but lack it.
Manual detection in Chi involves examining your middleware chain. Look for these warning signs:
// Vulnerable pattern - missing CSRF middleware
r := chi.NewRouter()
r.Use(middleware.Logger)
r.Use(middleware.Recoverer)
r.Use(middleware.Authenticator) // Only authenticates, doesn't prevent CSRF
r.Post("/api/v1/orders", createOrder)
r.Put("/api/v1/profile", updateProfile)middleBrick specifically flags Chi applications that accept state-changing requests without proper anti-CSRF mechanisms, providing severity ratings based on the potential impact of successful CSRF attacks.
Chi-Specific Remediation
Remediating CSRF in Chi applications leverages Go's ecosystem and Chi's middleware architecture. The most robust approach uses double-submit cookies or synchronizer tokens with proper middleware integration.
First, implement CSRF middleware in your Chi chain. Here's a production-ready example using the gorilla/csrf package:
package main
import (
"github.com/go-chi/chi/v5"
"github.com/go-chi/chi/v5/middleware"
"github.com/gorilla/csrf"
"net/http"
)
func main() {
r := chi.NewRouter()
// Standard middleware
r.Use(middleware.Logger)
r.Use(middleware.Recoverer)
// CSRF protection - key must be 32 bytes
csrfKey := []byte("32-byte-long-auth-key-here!!!!")
r.Use(csrf.Protect(
csrfKey,
csrf.Secure(false), // Set to true in production with HTTPS
csrf.HttpOnly(false), // Allow JavaScript access if needed
csrf.Path("/"),
))
// Protected routes
r.Post("/api/v1/users/update", updateUserHandler)
r.Put("/api/v1/admin/settings", adminSettingsHandler)
// Public routes (no CSRF needed)
r.Get("/api/v1/public", publicHandler)
http.ListenAndServe(":3000", r)
}This middleware automatically validates CSRF tokens for state-changing requests and generates new tokens for each response. The csrf.Token(r) function provides the token for your templates:
<input type="hidden" name="_csrf" value="{{.csrfToken}}">For API-only Chi applications that serve JSON clients, consider token-based CSRF protection:
type csrfMiddleware struct {
next http.Handler
key []byte
}
func (c *csrfMiddleware) ServeHTTP(w http.ResponseWriter, r *http.Request) {
if r.Method == "POST" || r.Method == "PUT" || r.Method == "DELETE" {
// Check for X-CSRF-Token header
token := r.Header.Get("X-CSRF-Token")
expected := computeToken(r, c.key)
if token != expected {
http.Error(w, "CSRF token missing or incorrect", http.StatusBadRequest)
return
}
}
c.next.ServeHTTP(w, r)
}
func WithCSRF(next http.Handler, key []byte) http.Handler {
return &csrfMiddleware{next: next, key: key}
}Mount this middleware in your Chi chain before handlers that modify state. For comprehensive protection, combine this with same-site cookie attributes and validate the Origin/Referer headers for additional defense in depth.