Overview
Broken Object Property Level Authorization vulnerabilities arise when an application correctly enforces access to a resource as a whole but fails to restrict access to individual properties within that resource. This can allow unauthorized users to discover or receive sensitive fields (for example, emails, salaries, or internal flags) even when they should not have visibility to those properties. The real-world CVE-2026-35413 demonstrates how a misconfigured introspection path in Directus could expose the SDL-like schema for unauthenticated or partially authenticated users, effectively leaking the structure of the system and its relationships. Although Directus is not Go (Gin), the same class of flaw can exist in Go services if you only gate access to a resource at the object level and skip per-field checks or field projection when serializing responses, leading to information exposure (CWE-200). In a Go (Gin) context, you might fetch a User record and marshal it entirely to JSON, including private fields, instead of building a response that only includes allowed properties for the current viewer.
In Go with Gin, a common pitfall is returning a model instance or a generic map with all fields after a database fetch, without considering the viewer's permissions for each field. This results in broken object property level authorization: the actor can infer or access fields they should not. The remediation is to implement explicit field-level whitelisting or projection: determine which fields the viewer is allowed to see and construct the response object accordingly (or use DTOs) rather than exposing the full underlying data structure. The provided code fixes demonstrate a vulnerable endpoint that returns the full user object and a fixed endpoint that applies per-field checks to selectively include sensitive properties based on the viewer's role or ownership.
Remediation guidance aligns with the CVE context by emphasizing that protecting only resource-level access is insufficient; you must enforce per-field access rules and verify them at each serialization boundary. Regular tests and code reviews should confirm that all fields are properly controlled, especially for endpoints that return user or meta-information. This approach reduces the risk of information disclosure even when business logic grants access to a resource, ensuring that the smallest necessary surface area is exposed to each caller.
Affected Versions
Directus < 11.16.1
Code Fix Example
Go (Gin) API Security Remediation
package main
import (
"net/http"
"github.com/gin-gonic/gin"
)
type User struct {
ID int `json:"id"`
Username string `json:"username"`
Email string `json:"email"`
Role string `json:"role"`
}
type Viewer struct {
ID int
IsAdmin bool
}
func main() {
r := gin.Default()
// Vulnerable endpoint: returns full user object regardless of viewer permissions
r.GET("/vuln/user/:id", vulnerableGetUser)
// Fixed endpoint: applies per-field authorization to filter response fields
r.GET("/fix/user/:id", fixedGetUser)
r.Run(":8080")
}
func vulnerableGetUser(c *gin.Context) {
// Fake user retrieval (would be from DB in real app)
user := User{ID: 1, Username: "alice", Email: "[email protected]", Role: "member"}
// Insecure: returns all fields irrespective of viewer
c.JSON(http.StatusOK, user)
}
func fixedGetUser(c *gin.Context) {
// Fake user retrieval
user := User{ID: 1, Username: "alice", Email: "[email protected]", Role: "member"}
// Fake viewer derived from request (in production, extract from JWT/session)
viewer := Viewer{ID: 2, IsAdmin: false}
resp := gin.H{
"id": user.ID,
"username": user.Username,
}
// Property-level access: allow Email and Role only to admins or the owner
if viewer.IsAdmin || viewer.ID == user.ID {
resp["email"] = user.Email
resp["role"] = user.Role
}
c.JSON(http.StatusOK, resp)
}