Broken Object Property Level Authorization

Broken Object Property Level Authorization in Go (Gin) [GHSA-8g7g-hmwm-6rv2]

[Updated May 2026] Updated GHSA-8g7g-hmwm-6rv2

Overview

Broken Object Property Level Authorization in Go (Gin) can expose resources when an API uses an ID in the request path to fetch data without verifying ownership. Even with authentication, if handlers rely on the object ID alone without checking that the current user has rights to access that specific object, attackers can enumerate or access other users' data. In real-world Go/Gin apps, this manifests when the handler queries a resource by id and returns it directly if found, without verifying that resource.OwnerID matches the authenticated user ID. Because Gin context often carries user identity after middleware, omission means any authenticated user can access any owned object. Impact includes data leakage, privilege escalation, and broader exposure across endpoints that share patterns. Remediation is to enforce object-level access checks, typically by validating ownership or applying an allow/deny policy before returning the object. In addition, ensure consistent patterns across APIs, add tests, log decisions, and avoid implicit trust. This guide provides a Go (Gin) specific remediation pattern with concrete code examples and testing considerations.

Code Fix Example

Go (Gin) API Security Remediation
package main

import (
  "net/http"
  "github.com/gin-gonic/gin"
)

type Resource struct {
  ID      string
  OwnerID string
  Data    string
}

type User struct { ID string }

var resources = map[string]Resource{
  "1": {ID: "1", OwnerID: "u1", Data: "secret"},
}

func main() {
  r := gin.Default()
  // Simulated authentication for demonstration
  r.Use(mockAuthMiddleware)
  r.GET("/vuln/resource/:id", GetResourceVulnerable)
  r.GET("/secure/resource/:id", GetResourceFixed)
  r.Run(":8080")
}

func mockAuthMiddleware(c *gin.Context) {
  // In a real application, replace with actual authentication
  c.Set("user", User{ID: "u1"})
  c.Next()
}

// Vulnerable: no authorization check against resource.OwnerID
func GetResourceVulnerable(c *gin.Context) {
  id := c.Param("id")
  res, ok := resources[id]
  if !ok {
    c.JSON(http.StatusNotFound, gin.H{"error": "not found"})
    return
  }
  c.JSON(http.StatusOK, res)
}

// Fixed: verify ownership before returning the resource
func GetResourceFixed(c *gin.Context) {
  id := c.Param("id")
  userVal, exists := c.Get("user")
  if !exists {
    c.JSON(http.StatusUnauthorized, gin.H{"error": "unauthorized"})
    return
  }
  u := userVal.(User)
  res, ok := resources[id]
  if !ok {
    c.JSON(http.StatusNotFound, gin.H{"error": "not found"})
    return
  }
  if res.OwnerID != u.ID {
    c.JSON(http.StatusForbidden, gin.H{"error": "forbidden"})
    return
  }
  c.JSON(http.StatusOK, res)
}

CVE References

Choose which optional cookies to allow. You can change this any time.