Provenance/Integrity preservation in provisioning API (authorization/integrity safeguard)

HIGH
grafana/grafana
Commit: 75e72827c9eb
Affected: Grafana 12.x prior to 12.4.0 (provisioning of ngalert alert rules).
2026-05-06 20:10 UTC

Description

Security hardening: The change enforces immutability of alert provenance for existing rules during provisioning updates. If a stored provenance exists and a provisioning request attempts to change it, the API now returns a structured provenance mismatch error (using errProvenanceMismatch) with a 409 Conflict semantics. This prevents provenance metadata tampering and strengthens integrity/authentication guarantees around alert rule provisioning.

Commit Details

Author: Khalil Haji

Date: 2026-05-06 19:45 UTC

Message:

Alerting: return 409 when changing provenance isn't allowed in provisioning APIs (#124178) * Alerting: return 409 when changing provenance isn't allowed * update tests

Triage Assessment

Vulnerability Type: Authentication/Authorization bypass

Confidence: HIGH

Reasoning:

The commit enforces a check that prevents changing the provenance of an alert rule during provisioning updates and returns a 409 with a structured error when a mismatch is detected. This prevents tampering with provenance metadata, which is an integrity/authentication-related safeguard and reduces the risk of unauthorized rule modification.

Verification Assessment

Vulnerability Type: Provenance/Integrity preservation in provisioning API (authorization/integrity safeguard)

Confidence: HIGH

Affected Versions: Grafana 12.x prior to 12.4.0 (provisioning of ngalert alert rules).

Code Diff

diff --git a/pkg/services/ngalert/provisioning/alert_rules.go b/pkg/services/ngalert/provisioning/alert_rules.go index 2a394eaf1ce43..51a261ec53ec8 100644 --- a/pkg/services/ngalert/provisioning/alert_rules.go +++ b/pkg/services/ngalert/provisioning/alert_rules.go @@ -820,7 +820,13 @@ func (service *AlertRuleService) UpdateAlertRule(ctx context.Context, user ident return models.AlertRule{}, err } if storedProvenance != provenance && storedProvenance != models.ProvenanceNone { - return models.AlertRule{}, fmt.Errorf("cannot change provenance from '%s' to '%s'", storedProvenance, provenance) + return models.AlertRule{}, errProvenanceMismatch.Build(errutil.TemplateData{ + Public: map[string]interface{}{ + "ProvidedProvenance": provenance, + "StoredProvenance": storedProvenance, + "Operation": "update", + }, + }) } if rule.NotificationSettings != nil { validator, err := service.nsValidatorProvider.Validator(ctx, rule.OrgID) diff --git a/pkg/services/ngalert/provisioning/alert_rules_test.go b/pkg/services/ngalert/provisioning/alert_rules_test.go index 359c2f04e47ae..9d4be8ba4fd5c 100644 --- a/pkg/services/ngalert/provisioning/alert_rules_test.go +++ b/pkg/services/ngalert/provisioning/alert_rules_test.go @@ -626,6 +626,7 @@ func TestIntegrationAlertRuleService(t *testing.T) { require.NoError(t, err) } else { require.Error(t, err) + require.True(t, errProvenanceMismatch.Base.Is(err)) } }) }
← Back to Alerts View on GitHub →