Information Disclosure / Improper Access Control (RBAC bypass on team resources in unified storage)

HIGH
grafana/grafana
Commit: 51bb33b28023
Affected: < 12.4.0
2026-07-03 07:33 UTC

Description

Security fix: The commit adds 'teams' to the iam.grafana.app allowlist in the authzLimitedClient, ensuring RBAC checks are applied to team search/list/read in unified storage. Prior to this change, any resource not explicitly on the allowlist defaulted to allow-all, which allowed users to enumerate or view all teams in unified storage (specifically in dual-writer mode 4/5). This created an information disclosure vulnerability where unauthorized users could discover team names (and potentially associated metadata) they should not have access to. The fix ensures that team-related operations are evaluated by the real access control client, aligning teams with users, dashboards, and folders in RBAC. The production impact is mitigated by migrating teams to unified storage and by ensuring authorization is consistently enforced for teams as with other resources.

Proof of Concept

PoC (pre-fix behavior vs post-fix behavior): Prerequisites: - Grafana instance with unified storage enabled and dual-writer mode (mode 4/5). - Teams exist: TeamA (accessible to user alice) and TeamB (not accessible to alice). - Alice has limited/no read permission to TeamB but needs to test team discovery via API. - Admin or a user with sufficient rights creates the two teams and assigns permissions accordingly. 1) Authenticate as alice and obtain a token: curl -s -X POST -H 'Content-Type: application/json' -d '{"user":"alice","password":"<password>"}' https://grafana.example/api/login/oauth (or use a session cookie/ Bearer token as your setup requires) TOKEN_A="<alice_token>" 2) Before fix (vulnerable path): Alice lists teams via the RBAC-protected endpoint. Due to the missing allowlist entry for teams, the authorization check short-circuits to allow-all and returns all teams, including TeamB. curl -s -H "Authorization: Bearer $TOKEN_A" https://grafana.example/api/teams/search?query= # Expected (before fix): {"teams":[{"name":"TeamA"},{"name":"TeamB"},...]} regardless of alice's real permissions 3) After applying the fix (RBAC for teams in the allowlist): Alice should only see teams she is allowed to read (e.g., TeamA). curl -s -H "Authorization: Bearer $TOKEN_A" https://grafana.example/api/teams/search?query= # Expected (after fix): {"teams":[{"name":"TeamA"}]} 4) Optional negative test: With a user who has no team read permissions at all, the response should be empty or only include teams explicitly allowed for that user.

Commit Details

Author: Cory Forseth

Date: 2026-07-03 07:29 UTC

Message:

Unified storage: Enforce RBAC for team search/list/read (#127788) fix(unified-storage): enforce RBAC for team search/list/read The authzLimitedClient only enforces authorization for group/resource pairs in its allowlist; anything unlisted short-circuits to allow-all in Check/Compile/BatchCheck. iam.grafana.app/teams was missing, so once teams read from unified storage (dual-writer mode 4/5) every user could see every team via searchTeams/list/read regardless of teams:read. Add teams to the iam.grafana.app allowlist so team authorization is resolved by the real access client, matching users, dashboards, and folders. Verified against a mode-5 environment: scoped users now see only the teams they can read, wildcard users see all, filtered by the storage layer before pagination. Not currently reachable in production, which still reads teams from legacy storage (SQL ac.Filter); this closes the gap for the in-progress teams->unified migration. Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>

Triage Assessment

Vulnerability Type: Information Disclosure

Confidence: HIGH

Reasoning:

The commit changes the authorization allowlist to include teams under iam.grafana.app, ensuring RBAC checks apply to team search/list/read in unified storage. Previously, unlisted resources defaulted to allow-all, allowing users to enumerate/view all teams. This directly fixes an authorization bypass and reduces information disclosure risk.

Verification Assessment

Vulnerability Type: Information Disclosure / Improper Access Control (RBAC bypass on team resources in unified storage)

Confidence: HIGH

Affected Versions: < 12.4.0

Code Diff

diff --git a/pkg/storage/unified/resource/access.go b/pkg/storage/unified/resource/access.go index 2b13aef3b47d..38d4f392b31d 100644 --- a/pkg/storage/unified/resource/access.go +++ b/pkg/storage/unified/resource/access.go @@ -104,7 +104,7 @@ func NewAuthzLimitedClient(client claims.AccessClient, opts AuthzOptions) claims allowlist: groupResource{ "dashboard.grafana.app": map[string]interface{}{"dashboards": nil}, "folder.grafana.app": map[string]interface{}{"folders": nil}, - "iam.grafana.app": map[string]interface{}{"users": nil}, + "iam.grafana.app": map[string]interface{}{"users": nil, "teams": nil}, }, logger: logger, metrics: newMetrics(opts.Registry),
← Back to Alerts View on GitHub →