HIGH mass assignmentgincockroachdb

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 pgx to 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 IDNameSeverity
CWE-915Mass Assignment HIGH

Frequently Asked Questions

Can middleBrick detect mass assignment risks in Gin endpoints that use CockroachDB?
Yes. middleBrick runs unauthenticated checks including Property Authorization and BFLA/Privilege Escalation that can identify endpoints where HTTP binding maps directly to database models without field whitelisting, regardless of the database backend.
Does using an ORM with CockroachDB prevent mass assignment in Gin?
Not automatically. ORMs that map entire structs can still propagate over-broad fields if the struct includes user-supplied values. Always bind to a restricted DTO and explicitly select columns to insert or update.