Mass Assignment in Gin with Cockroachdb
Mass Assignment in Gin with Cockroachdb — how this specific combination creates or exposes the vulnerability
Mass assignment in a Gin application that uses CockroachDB as the backend arises when HTTP request parameters are directly bound to database models or DTOs without explicit field filtering. In Go, this typically occurs when developers use c.ShouldBind (or ShouldBindJSON) to map incoming JSON into a struct that is then passed to CockroachDB via an ORM or raw query, and the struct contains fields that should never be user-controlled (e.g., ID, CreatedAt, Role, IsAdmin).
With CockroachDB, which behaves like PostgreSQL wire-protocol-wise, the risk is not a database-specific injection but an application-layer authorization bypass: if the bound struct includes sensitive or mutable fields and those values are used in INSERT or UPDATE statements without whitelisting, an attacker can set arbitrary values. For example, a user could supply "role":"admin" in JSON and, because the ORM or Exec uses the full struct, the database will store that elevated role. This is a BOLA/IDOR and BFLA-style issue mapped to the Property Authorization check run by middleBrick.
The Gin framework does not validate which fields are safe to bind; it only ensures the JSON keys map to struct fields by name. If the developer relies on CockroachDB’s constraints (e.g., a CHECK or row-level security) as the sole guard, they may still face logical privilege escalation because constraints can be complex to maintain and may not cover all business rules. middleBrick’s 12 security checks, including Property Authorization and BFLA/Privilege Escalation, are designed to detect such unchecked binding paths in unauthenticated scans.
Consider a user update endpoint that binds all fields and then builds an upsert with pgx:
// Unsafe: binds all fields, including ID and Role
type UserUpdate struct {
ID int64 `json:"id"`
Email string `json:"email"`
Username string `json:"username"`
Role string `json:"role"` // attacker-controlled
IsActive bool `json:"is_active"`
}
func UpdateUser(c *gin.Context) {
var u UserUpdate
if err := c.ShouldBindJSON(&u); err != nil {
c.JSON(400, gin.H{"error": err.Error()})
return
}
// Direct use of u.ID and u.Role in query enables mass assignment
_, err := db.Exec(context.Background(),
`INSERT INTO users (id, email, username, role, is_active) VALUES ($1,$2,$3,$4,$5) ON CONFLICT (id) DO UPDATE SET email=$2, username=$3, role=$4, is_active=$5`,
u.ID, u.Email, u.Username, u.Role, u.IsActive)
if err != nil {
c.JSON(500, gin.H{"error": err.Error()})
return
}
c.Status(200)
}
If an attacker sends {"id":999,"role":"admin"} but is not allowed to modify other users or assume admin privileges, the mass assignment silently applies those values to CockroachDB. The vulnerability is not in CockroachDB itself but in how Gin binds and forwards data; however, CockroachDB will faithfully execute the malicious assignments unless upstream checks exist. middleBrick’s OpenAPI/Swagger analysis can expose such mismatches by cross-referencing spec definitions with runtime parameter expectations.
To mitigate within Gin + CockroachDB, always bind to a minimal DTO, explicitly whitelist mutable fields, and map to database columns via parameterized queries that do not rely on struct-to-column mirroring for sensitive fields. This aligns with the remediation guidance provided in middleBrick’s findings and helps satisfy Property Authorization and Input Validation checks.
Cockroachdb-Specific Remediation in Gin — concrete code fixes
Remediation focuses on strict input binding, explicit field selection, and avoiding struct passthrough to SQL. Use separate request structs that omit sensitive or immutable fields, validate server-side, and construct SQL with named parameters that only include permitted columns.
1) Define a request DTO without sensitive fields
// SafeRequest only includes fields the client is allowed to set
type UserUpdateRequest struct {
Email string `json:"email" binding:"required,email"`
Username string `json:"username" binding:"required,min=3,max=32"`
IsActive *bool `json:"is_active,omitempty"`
// Role and ID are omitted; server applies defaults/roles
2) Bind, validate, then map to database columns explicitly
func UpdateUserSafe(c *gin.Context) {
var req UserUpdateRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(400, gin.H{"error": err.Error()})
return
}
// Server-side defaults and authorization checks
updatedRole := "user" // default, not from client
// Only pass whitelisted columns to the query
_, err := db.Exec(context.Background(),
`UPDATE users SET email=$1, username=$2, role=$3, is_active=$4 WHERE id=$5`,
req.Email, req.Username, updatedRole, req.IsActive, c.Param("id"))
if err != nil {
c.JSON(500, gin.H{"error": err.Error()})
return
}
c.Status(200)
}
3) Use explicit column lists in INSERT/UPDATE (avoid SELECT * or struct-based ORM auto-mapping)
// When inserting new users, do not allow client to set ID or role via request
func CreateUserSafe(c *gin.Context) {
var req struct {
Email string `json:"email" binding:"required,email"`
Username string `json:"username" binding:"required,min=3,max=32"`
}
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(400, gin.H{"error": err.Error()})
return
}
// Server-assigned defaults
role := "user"
createdAt := time.Now().UTC()
var id int64
err := db.QueryRow(context.Background(),
`INSERT INTO users (email, username, role, created_at) VALUES ($1,$2,$3,$4) RETURNING id`,
req.Email, req.Username, role, createdAt).Scan(&id)
if err != nil {
c.JSON(500, gin.H{"error": err.Error()})
return
}
c.JSON(201, gin.H{"id": id})
}
4) Leverage CockroachDB’s strengths safely
- Keep using CHECK constraints and Row-Level Security (RLS) as defense-in-depth, but do not rely on them alone to enforce authorization from Gin inputs.
- Use prepared statements via
pgxto avoid SQL injection; this complements mass assignment prevention by ensuring structure is not abused at protocol level.
These patterns reduce the attack surface exposed through Gin binding and ensure only intended fields reach CockroachDB. middleBrick’s CLI (middlebrick scan <url>) and GitHub Action can validate that your endpoints follow such strict binding practices by detecting over-broad struct usage in unauthenticated scans.
Related CWEs: propertyAuthorization
| CWE ID | Name | Severity |
|---|---|---|
| CWE-915 | Mass Assignment | HIGH |