Broken Object Level Authorization

Broken Object Level Authorization in Go (Gin) [Apr 2026] [GHSA-pp79-hqv6-vmc3]

[Updated Apr 2026] Updated GHSA-pp79-hqv6-vmc3

Overview

Broken Object Level Authorization (BOLA) occurs when APIs expose object data without verifying that the requester has rights to access that object. In Go with Gin, handlers frequently read an object ID from the URL and fetch the resource without checking ownership, enabling one user to access another's data.\n\nIn real-world Go/Gin apps this manifests as endpoints that allow GET, PATCH, or DELETE by ID without cross-checks against a user identity obtained via JWT or session. The impact includes data leakage, privilege escalation, and potential regulatory exposure.\n\nThis guide shows how BOLA can appear in Gin apps, and provides concrete changes to enforce object-level authorization, including example code, remediation steps, and testing considerations.\n\nNote: CVE IDs are not provided in this request; this guide describes common patterns and defenses rather than a specific advisory.

Code Fix Example

Go (Gin) API Security Remediation
package main\n\nimport (\n  \"net/http\"\n  \"github.com/gin-gonic/gin\"\n)\n\ntype Resource struct {\n  ID string\n  OwnerID string\n  Data string\n}\n\nfunc main() {\n  r := gin.Default()\n\n  // In-memory data store\n  resources := map[string]Resource{\n    \"1\": {ID: \"1\", OwnerID: \"alice\", Data: \"secret1\"},\n    \"2\": {ID: \"2\", OwnerID: \"bob\", Data: \"secret2\"},\n  }\n\n  // Vulnerable endpoint: does not enforce object-level authorization\n  r.GET(\"/vuln/resources/:id\", func(c *gin.Context) {\n    id := c.Param(\"id\")\n    res, ok := resources[id]\n    if !ok {\n      c.JSON(http.StatusNotFound, gin.H{\"error\": \"not found\"})\n      return\n    }\n    // No ownership check: any authenticated user can access any resource\n    c.JSON(http.StatusOK, gin.H{\"id\": res.ID, \"owner\": res.OwnerID, \"data\": res.Data})\n  })\n\n  // Quick auth helper: read user from X-User header\n  r.GET(\"/secure/resources/:id\", func(c *gin.Context) {\n    id := c.Param(\"id\")\n    res, ok := resources[id]\n    if !ok {\n      c.JSON(http.StatusNotFound, gin.H{\"error\": \"not found\"})\n      return\n    }\n    user := c.GetHeader(\"X-User\")\n    if user == \"\" {\n      c.JSON(http.StatusUnauthorized, gin.H{\"error\": \"unauthorized\"})\n      return\n    }\n    if res.OwnerID != user {\n      c.JSON(http.StatusForbidden, gin.H{\"error\": \"forbidden\"})\n      return\n    }\n    c.JSON(http.StatusOK, gin.H{\"id\": res.ID, \"owner\": res.OwnerID, \"data\": res.Data})\n  })\n\n  r.Run(\":8080\")\n}\n

CVE References

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