Mass Assignment in Chi
How Mass Assignment Manifests in Chi
Mass assignment vulnerabilities in Chi-based APIs occur when the framework automatically binds HTTP request parameters to struct fields without proper validation or filtering. This becomes particularly dangerous when Chi's router automatically decodes JSON request bodies into Go structs, potentially allowing attackers to set fields they shouldn't have access to.
Consider a typical Chi API endpoint that creates a user account:
type User struct {
ID int64 `json:"id"`
Email string `json:"email"`
Password string `json:"password"`
IsAdmin bool `json:"is_admin"`
CreatedAt string `json:"created_at"`
}
func CreateUser(w http.ResponseWriter, r *http.Request) {
var user User
if err := json.NewDecoder(r.Body).Decode(&user); err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
// Store user in database...
}An attacker can exploit this by sending a request like:
POST /api/users HTTP/1.1
Content-Type: application/json
{
"email": "[email protected]",
"password": "password123",
"is_admin": true
}Without proper validation, the API will happily create an admin user. This vulnerability is especially common in Chi applications because the framework's simplicity encourages direct struct binding without considering field-level security.
Another Chi-specific manifestation occurs with nested structs and pointer fields. Consider:
type UserProfile struct {
Bio string `json:"bio"`
Status string `json:"status"`
}
type User struct {
ID int64 `json:"id"`
Email string `json:"email"`
Profile *UserProfile `json:"profile"`
}Attackers can exploit pointer fields to create unexpected object graphs or trigger nil pointer dereferences if the application doesn't handle them properly.
Chi's middleware ecosystem can also introduce mass assignment risks. When using middleware that automatically populates request context with user data, developers might inadvertently trust this data without validation:
func RequireAuth(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// Extract user from token...
user := &User{ID: 123, Email: "[email protected]"}
ctx := context.WithValue(r.Context(), "user", user)
next.ServeHTTP(w, r.WithContext(ctx))
})
}
func UpdateUser(w http.ResponseWriter, r *http.Request) {
user := r.Context().Value("user").(*User)
// No validation - trusts context data blindly
if err := json.NewDecoder(r.Body).Decode(&user); err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
}This pattern allows attackers who can manipulate context data to escalate privileges or modify unauthorized fields.
Chi-Specific Detection
Detecting mass assignment vulnerabilities in Chi applications requires both static analysis and dynamic scanning. middleBrick's black-box scanning approach is particularly effective for Chi APIs because it tests the actual runtime behavior without needing source code access.
For Chi applications, middleBrick automatically tests for mass assignment by:
- Sending crafted JSON payloads with unexpected fields to see if they're accepted
- Testing nested struct binding by including deeply nested objects
- Checking pointer field behavior with null and valid object values
- Verifying that sensitive fields like admin flags, IDs, and timestamps aren't writable
- Testing context-based authentication bypass scenarios
Manual detection in Chi code involves looking for these patterns:
// Dangerous pattern - direct struct binding
func CreateHandler(w http.ResponseWriter, r *http.Request) {
var data MyStruct
json.NewDecoder(r.Body).Decode(&data)
// No field filtering or validation
db.Create(&data)
}
// Safer pattern with field filtering
func CreateHandler(w http.ResponseWriter, r *http.Request) {
var input map[string]interface{}
json.NewDecoder(r.Body).Decode(&input)
// Whitelist approach
allowed := map[string]interface{}{}
for _, field := range []string{"name", "email", "password"} {
if val, exists := input[field]; exists {
allowed[field] = val
}
}
var data MyStruct
if err := mapstructure.Decode(allowed, &data); err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
db.Create(&data)
}middleBrick's OpenAPI analysis is particularly useful for Chi applications that use code generation or follow OpenAPI specifications. The scanner can identify discrepancies between the documented API contract and the actual implementation, catching cases where the spec allows certain fields but the implementation should restrict them.
During a middleBrick scan, you'll see specific findings like:
Mass Assignment Vulnerability (Critical)
Endpoint: POST /api/users
Risk: Attackers can set admin=true, id, or created_at fields
Remediation: Implement field whitelisting or use struct tags to exclude sensitive fieldsChi-Specific Remediation
Remediating mass assignment vulnerabilities in Chi applications requires a defense-in-depth approach. The most effective strategy combines Chi's native features with Go best practices.
First, use struct tags to control JSON binding behavior:
type User struct {
ID int64 `json:"id" json:"-" db:"id"`
Email string `json:"email" db:"email"`
Password string `json:"password" db:"password"`
IsAdmin bool `json:"is_admin" db:"is_admin" validate:"-"`
CreatedAt string `json:"created_at" db:"created_at" validate:"-"`
}
// Custom unmarshaler to reject sensitive fields
func (u *User) UnmarshalJSON(data []byte) error {
var raw map[string]interface{}
if err := json.Unmarshal(data, &raw); err != nil {
return err
}
// Whitelist allowed fields
allowed := map[string]interface{}{}
for _, field := range []string{"email", "password"} {
if val, exists := raw[field]; exists {
allowed[field] = val
}
}
// Convert back to JSON and unmarshal to struct
filtered, _ := json.Marshal(allowed)
return json.Unmarshal(filtered, u)
}For Chi-specific middleware patterns, implement proper context validation:
func RequireAuth(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// Validate token and extract claims
claims, err := ValidateToken(r.Header.Get("Authorization"))
if err != nil {
http.Error(w, "Unauthorized", http.StatusUnauthorized)
return
}
// Create user object with only allowed fields
user := &User{
ID: claims.UserID,
Email: claims.Email,
}
ctx := context.WithValue(r.Context(), "user", user)
next.ServeHTTP(w, r.WithContext(ctx))
})
}
func UpdateUser(w http.ResponseWriter, r *http.Request) {
user := r.Context().Value("user").(*User)
// Create separate struct for update
var update struct {
Name string `json:"name"`
Bio string `json:"bio"`
Website string `json:"website"`
}
if err := json.NewDecoder(r.Body).Decode(&update); err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
// Only update allowed fields
db.Model(user).Updates(update)
}middleBrick's continuous monitoring in the Pro plan can help verify that your remediation efforts are effective. After implementing fixes, run another scan to ensure the mass assignment vulnerabilities are resolved and that your API security score improves.
For team adoption, integrate middleBrick into your Chi development workflow using the GitHub Action. This ensures that any new endpoints are automatically scanned for mass assignment and other API security issues before they reach production.
Related CWEs: propertyAuthorization
| CWE ID | Name | Severity |
|---|---|---|
| CWE-915 | Mass Assignment | HIGH |