Broken Object Property Level Authorization

Broken Object Property Level Authorization in Go (Gin) [GHSA-67cr-jmh8-4jpq]

[Updated Mar 2026] Updated GHSA-67cr-jmh8-4jpq

Overview

Broken Object Property Level Authorization in Go (Gin) is a common source of data leakage when handlers fetch resources by id without validating that the requester owns or is permitted to access the resource. In real-world apps, attackers can enumerate IDs or manipulate parameters to access unrelated user data, leading to horizontal privilege escalation and privacy violations. When such flaws exist in APIs serving sensitive data, the impact ranges from unauthorized data exposure to potential compromise of multi-tenant boundaries, with downstream consequences for compliance and user trust.

Code Fix Example

Go (Gin) API Security Remediation
// Vulnerable and fixed endpoints are exposed side-by-side in a single Gin app for demonstration.
package main

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

type Widget struct {
  ID      int64
  OwnerID int64
  Data    string
}

var widgets = map[int64]Widget{
  1: {ID: 1, OwnerID: 10, Data: "secret A"},
  2: {ID: 2, OwnerID: 20, Data: "secret B"},
}

func main() {
  r := gin.Default()
  // Vulnerable: no per-object authorization
  r.GET("/widgets/:id", vulnerable)
  // Fixed: authorization checks that the requester owns the object
  r.GET("/widgets-fixed/:id", fixed)
  r.Run(":8080")
}

func vulnerable(c *gin.Context) {
  id, _ := strconv.ParseInt(c.Param("id"), 10, 64)
  if w, ok := widgets[id]; ok {
    c.JSON(http.StatusOK, w)
    return
  }
  c.Status(http.StatusNotFound)
}

func fixed(c *gin.Context) {
  id, _ := strconv.ParseInt(c.Param("id"), 10, 64)
  w, ok := widgets[id]
  if !ok {
    c.Status(http.StatusNotFound)
    return
  }
  // Simple user identity from header for demonstration
  userID := getUserID(c)
  if w.OwnerID != userID {
    c.JSON(http.StatusForbidden, map[string]string{"error": "forbidden"})
    return
  }
  c.JSON(http.StatusOK, w)
}

func getUserID(c *gin.Context) int64 {
  s := c.GetHeader("X-User-ID")
  id, _ := strconv.ParseInt(s, 10, 64)
  return id
}

CVE References

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