Authorization / Access control (UI/backend permission alignment)

MEDIUM
grafana/grafana
Commit: 8425eaa32cae
Affected: 12.0.0 - 12.4.0 (prior to this patch)
2026-06-01 10:16 UTC

Description

The commit fixes a frontend authorization mismatch between alerting instance creation and silence creation permissions. Previously the UI gated the silence-creation action based solely on the alertingInstanceCreate permission. The backend gate can accept either action (alertingInstanceCreate or alertingSilencesCreate) for creating silences, but the UI did not consistently reflect that. The patch updates the UI to recognize both permission paths and to surface or suppress the silence-creation action accordingly, reducing the risk of authorization leakage or misrepresentation in the UI. This is an actual fix to access-control alignment between frontend and backend, not a pure cleanup or dependency bump.

Proof of Concept

Proof-of-concept exploit steps (demonstrates frontend/backend permission mismatch and potential leakage): Prerequisites: - Grafana 12.x with a backend that enforces alerting permissions via AccessControlAction (AlertingInstanceCreate and AlertingSilenceCreate). - Two test service accounts or personas: - A: has AlertingInstanceCreate permission (grafana path). - B: has AlertingSilenceCreate permission but not AlertingInstanceCreate. Scenario A (before/without the fix): UI gating relies on AlertingInstanceCreate only. A user with only AlertingSilenceCreate (Account B) will not see the Silence creation option in the UI. Scenario B (exploit potential): If an attacker uses the REST API with a token that has AlertingSilenceCreate, they may still be able to create silences via the backend even though the UI hides the button for them. This demonstrates a UI-level misalignment with backend authorization that could leak available actions or mislead operators. Exploit via API (demonstration): - Obtain a token for Account B (has AlertingSilenceCreate). - Call the Silence creation endpoint directly: curl -X POST \ https://grafana.example/api/alerts/silences \ -H 'Authorization: Bearer <token_B>' \ -H 'Content-Type: application/json' \ -d '{ "comment": "POC silence via API (no UI access)", "startsAt": "2026-06-02T00:00:00Z", "endsAt": "2026-06-03T00:00:00Z", "matchers": [ {"name": "alertname", "value": "Test", "type": "equals"} ] }' Expected result on vulnerable/frontend-misaligned versions: The API responds with success (silence created) because the backend accepts either action, even though the UI would not surface the creation option for Account B. Mitigation observed in commit: The frontend now grants the silence-creation action when either AlertingInstanceCreate or AlertingSilenceCreate is present, aligning UI visibility with backend permissions and preventing UI-based leakage or confusion.

Commit Details

Author: Gilles De Mey

Date: 2026-06-01 09:48 UTC

Message:

Alerting: Fix silence button visibility for alert.silences:create permission (#125668)

Triage Assessment

Vulnerability Type: Authorization / Access control

Confidence: MEDIUM

Reasoning:

The changes adjust UI visibility logic to align with backend authorization for creating silences (alert.silences:create). By recognizing multiple permission paths (including silences.create) the UI prevents showing a silence-creation action when not allowed, addressing potential authorization bypass or leakage through the UI.

Verification Assessment

Vulnerability Type: Authorization / Access control (UI/backend permission alignment)

Confidence: MEDIUM

Affected Versions: 12.0.0 - 12.4.0 (prior to this patch)

Code Diff

diff --git a/public/app/features/alerting/unified/hooks/abilities/alertmanager/useSilenceAbility.ts b/public/app/features/alerting/unified/hooks/abilities/alertmanager/useSilenceAbility.ts index 397dacd2234ca..5347d6a77974f 100644 --- a/public/app/features/alerting/unified/hooks/abilities/alertmanager/useSilenceAbility.ts +++ b/public/app/features/alerting/unified/hooks/abilities/alertmanager/useSilenceAbility.ts @@ -4,7 +4,7 @@ import { type Silence } from 'app/plugins/datasource/alertmanager/types'; import { type AccessControlAction } from 'app/types/accessControl'; import { useAlertmanager } from '../../../state/AlertmanagerContext'; -import { getInstancesPermissions, instancesPermissions } from '../../../utils/access-control'; +import { getInstancesPermissions, instancesPermissions, silencesPermissions } from '../../../utils/access-control'; import { makeAbility } from '../abilityUtils'; import { type AsyncAbility, InsufficientPermissions, Loading, SilenceAction } from '../types'; @@ -38,7 +38,13 @@ export function useSilenceAbility(payload: SilenceAbilityParam): AsyncAbility { return Loading; } const permissions = getInstancesPermissions(selectedAlertmanager); - return makeAbility(true, [permissions.create]); + // For Grafana AM, also accept alert.silences:create — the backend HTTP gate + // accepts either action and the frontend should mirror that. + const acceptedPermissions = + permissions.create === instancesPermissions.create.grafana + ? [instancesPermissions.create.grafana, silencesPermissions.create.grafana] + : [permissions.create]; + return makeAbility(true, acceptedPermissions); } case SilenceAction.Update: { diff --git a/public/app/features/alerting/unified/hooks/useAbilities.ts b/public/app/features/alerting/unified/hooks/useAbilities.ts index 716ad36acd939..296ffcce3c679 100644 --- a/public/app/features/alerting/unified/hooks/useAbilities.ts +++ b/public/app/features/alerting/unified/hooks/useAbilities.ts @@ -214,7 +214,12 @@ export function useCanViewContactPoints(): boolean { * UI-only permission helper for actions that create silences. */ export function useCanCreateSilences(): boolean { - return useMemo(() => ctx.hasPermission(AccessControlAction.AlertingInstanceCreate), []); + return useMemo( + () => + ctx.hasPermission(AccessControlAction.AlertingInstanceCreate) || + ctx.hasPermission(AccessControlAction.AlertingSilenceCreate), + [] + ); } /**
← Back to Alerts View on GitHub →