Broken Object Property Level Authorization

Broken Object Property Level Authorization in Go (Gin) [CVE-2026-32265]

[Updated Mar 2026] Updated CVE-2026-32265

Overview

Broken Object Property Level Authorization (BOPLA) vulnerabilities allow attackers to access object-level data they should not see. CVE-2026-32265 demonstrates this in the Craft CMS Amazon S3 plugin, where unauthenticated users could list buckets via BucketsController->actionLoadBucketData() when possessing a valid CSRF token. This created data exposure by leaking the set of buckets the plugin could access, highlighting the risk of trusting tokens or global checks over per-object authorization. The same pattern can appear in Go (Gin) APIs if endpoints return object collections without verifying user permissions. In a Go Gin application, BOPLA manifests when a route returns a collection of resources (for example, buckets, documents, or orders) without filtering by the authenticated user's rights. Attackers can enumerate or discover resources by simply calling the endpoint, especially if there is no authentication, or if authentication exists but per-object checks are skipped or bypassable through tokens or CSRF-like parameters. The CVE illustrates that relying on a single token or token-protected endpoint is not enough when those tokens do not tie to per-object access. Remediation approach: enforce authentication and per-object authorization in the handler chain; ensure that every resource collection is filtered to only include objects owned or authorized for the current user; use robust auth (JWT/OAuth2) and proper middleware in Gin; validate tokens, set user identity in the context, and apply explicit ownership checks at query time. In tests, try enumerating objects with different users to ensure no leakage. Implementation note: The provided Go Gin example demonstrates a vulnerable endpoint that returns all buckets, followed by a fixed version that authenticates and filters by OwnerID. CVE-2026-32265 is the basis for understanding why such patterns leak data; applying these changes aligns with remediation guidance.

Affected Versions

2.0.2-2.2.4 (Craft CMS Amazon S3 plugin); fixed in 2.2.5

Code Fix Example

Go (Gin) API Security Remediation
package main

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

type Bucket struct { ID string; Name string; OwnerID string }

var buckets = []Bucket{
  {ID: "1", Name: "photos", OwnerID: "u1"},
  {ID: "2", Name: "logs", OwnerID: "u2"},
  {ID: "3", Name: "docs", OwnerID: "u1"},
}

func main() {
  r := gin.Default()

  // Vulnerable endpoint: returns all buckets without per-object authorization
  r.GET("/vulnerable/buckets", func(c *gin.Context) {
     c.JSON(http.StatusOK, buckets)
  })

  // Fixed endpoint: requires auth and filters per-user buckets
  secured := r.Group("/secured")
  secured.Use(authMiddleware)
  secured.GET("/buckets", func(c *gin.Context) {
     uid := c.GetString("userID")
     var userBuckets []Bucket
     for _, b := range buckets {
        if b.OwnerID == uid {
           userBuckets = append(userBuckets, b)
        }
     }
     c.JSON(http.StatusOK, userBuckets)
  })

  r.Run(":8080")
}

func authMiddleware(c *gin.Context) {
  auth := c.GetHeader("Authorization")
  if auth == "" {
     c.AbortWithStatus(http.StatusUnauthorized)
     return
  }
  parts := strings.SplitN(auth, " ", 2)
  if len(parts) != 2 || strings.ToLower(parts[0]) != "bearer" {
     c.AbortWithStatus(http.StatusUnauthorized)
     return
  }
  c.Set("userID", parts[1])
  c.Next()
}

CVE References

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