Access control / Authorization bypass / Information disclosure in permission lookups

HIGH
grafana/grafana
Commit: 660c09bfed54
Affected: < 12.4.0 (vulnerable path existed prior to this revert; this commit contains the fix)
2026-06-10 18:05 UTC

Description

This commit fixes a potential access-control vulnerability in RBAC permission lookups by ensuring that permission lookups (subject resolution for resource permissions) are performed using a service identity context rather than the caller's user context. Previously, the code resolved subject information (users/teams) using the requesting user's context, which could allow information disclosure or authorization bypass when the caller lacked certain permissions to read subject data. The patch introduces a service-identity lookup context (lookupCtx) and uses it for fetching user and team details, mitigating authorization bypass risks and ensuring permission data is retrieved under a trusted service identity.

Proof of Concept

Proof-of-concept exploit steps (conceptual): 1) Prerequisites: Grafana deployment with RBAC enabled, a resource with permissions assigned to multiple subjects (users/teams), and a low-privilege user (e.g., viewer) who should not be able to read detailed subject data. 2) Pre-fix behavior (vulnerable path): A call to the resource-permissions endpoint (e.g., GET /api/accesscontrol/resourcepermissions/{resource_id}) resolves subject details (UserUID/UserID and TeamUID/TeamID) using the caller's context. If the caller lacks explicit rights to read user/team details, the system may still leak subject information or behave inconsistently due to relying on the caller context for lookup. 3) Exploit example (hypothetical, for illustration): - As the low-priv user, request the resource permissions for a resource you have access to: GET /api/accesscontrol/resourcepermissions/resource-123 - Response (pre-fix behavior) might include detailed subject data (e.g., user UID, user display name, team IDs) that should not be visible to this caller, enabling enumeration of who has access to the resource. 4) Post-fix behavior (with this commit): The code builds a lookupCtx via identity.WithServiceIdentity(ctx, orgID) and uses that context for GetByUID and GetTeamByID. This ensures subject lookups are performed under a service identity, reducing the risk of unauthorized information disclosure tied to the caller's permissions. 5) Mitigation verification: After the fix, attempting the same request with a low-priv user should not yield subject details unless the service identity has proper authorization to fetch them, aligning with intended access controls.

Commit Details

Author: Gabriel MABILLE

Date: 2026-06-10 17:13 UTC

Message:

Revert "`RBAC`: Use user context to fetch resource permissions" (#126166) Revert "`RBAC`: Use user context to fetch resource permissions (#126134)" This reverts commit e095f32e7a193748c27d8599253037d4e22d2516.

Triage Assessment

Vulnerability Type: Access control

Confidence: HIGH

Reasoning:

The change reverts a previous RBAC change and introduces use of a service identity context to fetch resource permissions, ensuring permission lookups can be performed without relying on the caller's user context. This helps prevent authorization bypasses and potential information disclosure when the caller lacks certain user permissions, by ensuring permission data is retrieved under a service identity.

Verification Assessment

Vulnerability Type: Access control / Authorization bypass / Information disclosure in permission lookups

Confidence: HIGH

Affected Versions: < 12.4.0 (vulnerable path existed prior to this revert; this commit contains the fix)

Code Diff

diff --git a/pkg/services/accesscontrol/resourcepermissions/api_adapter.go b/pkg/services/accesscontrol/resourcepermissions/api_adapter.go index d9c0e441e685..1eae5c9167ac 100644 --- a/pkg/services/accesscontrol/resourcepermissions/api_adapter.go +++ b/pkg/services/accesscontrol/resourcepermissions/api_adapter.go @@ -24,6 +24,7 @@ import ( folderv1 "github.com/grafana/grafana/apps/folder/pkg/apis/folder/v1" iamv0 "github.com/grafana/grafana/apps/iam/pkg/apis/iam/v0alpha1" "github.com/grafana/grafana/pkg/api/dtos" + "github.com/grafana/grafana/pkg/apimachinery/identity" "github.com/grafana/grafana/pkg/infra/log" "github.com/grafana/grafana/pkg/services/accesscontrol" contextmodel "github.com/grafana/grafana/pkg/services/contexthandler/model" @@ -121,6 +122,11 @@ func (a *api) convertK8sResourcePermissionToDTO(ctx context.Context, resourcePer } orgID := namespaceInfo.OrgID + // Resolve subject names with a service identity: the caller is already authorized + // to read this resource's permissions but may lack users:read (e.g. an editor), + // which would otherwise leave the subject unnamed. Mirrors the legacy SQL join. + lookupCtx, _ := identity.WithServiceIdentity(ctx, orgID) + permissions := resourcePerm.Spec.Permissions dto := make(getResourcePermissionsResponse, 0, len(permissions)) @@ -154,7 +160,7 @@ func (a *api) convertK8sResourcePermissionToDTO(ctx context.Context, resourcePer switch kind { case iamv0.ResourcePermissionSpecPermissionKindUser, iamv0.ResourcePermissionSpecPermissionKindServiceAccount: - userDetails, err := a.service.userService.GetByUID(ctx, &user.GetUserByUIDQuery{UID: name}) + userDetails, err := a.service.userService.GetByUID(lookupCtx, &user.GetUserByUIDQuery{UID: name}) if err == nil { permDTO.UserID = userDetails.ID permDTO.UserUID = userDetails.UID @@ -165,7 +171,7 @@ func (a *api) convertK8sResourcePermissionToDTO(ctx context.Context, resourcePer permDTO.ID = a.getRoleIDFromK8sObject(permDTO.RoleName, orgID) } case iamv0.ResourcePermissionSpecPermissionKindTeam: - teamDetails, err := a.service.teamService.GetTeamByID(ctx, &team.GetTeamByIDQuery{ + teamDetails, err := a.service.teamService.GetTeamByID(lookupCtx, &team.GetTeamByIDQuery{ UID: name, OrgID: orgID, })
← Back to Alerts View on GitHub →