Grafana Enterprise SCIM User ID Collision / Impersonation (CVE-2025-41115)
by I3r1h0n · 2026-07-06
- Severity
- Critical
- CVE
- CVE-2025-41115
- Category
- web
- Affected product
- Grafana Enterprise / Grafana Cloud, SCIM provisioning component (/api/scim/v2/Users)
- Affected versions
- Grafana 12.x+ with SCIM provisioning configured (enableSCIM feature flag + user_sync_enabled set); fixed by upstream commit ca5d89812015ef2db3acc62826f73650450b331e
- Disclosed
- 2026-07-06
- Patch status
- unpatched
Tags
References
- https://github.com/I3r1h0n/GrafanaSCIMalform
- https://nvd.nist.gov/vuln/detail/CVE-2025-41115
- https://grafana.com/blog/2025/11/19/grafana-enterprise-security-update-critical-severity-security-fix-for-cve-2025-41115/
- https://advisories.gitlab.com/pkg/golang/github.com/grafana/grafana/CVE-2025-41115/
- https://blog.doyensec.com/2025/05/08/scim-hunting.html
Archive entry
intelseclab/poc-archiveMetadata
| Field | Value |
|---|---|
| Date Added | 2026-07-06 |
| Last Updated | 2026-07-06 |
| Author / Researcher | I3r1h0n |
| CVE / Advisory | CVE-2025-41115 |
| Category | web |
| Severity | Critical |
| CVSS Score | 10.0 (per NVD) |
| Status | PoC |
| Tags | grafana, grafana-enterprise, scim, user-impersonation, privilege-escalation, id-collision, python, docker, cwe-287 |
| Related | N/A |
Affected Target
| Field | Value |
|---|---|
| Software / System | Grafana Enterprise / Grafana Cloud, SCIM provisioning component (/api/scim/v2/Users) |
| Versions Affected | Grafana 12.x+ with SCIM provisioning configured (enableSCIM feature flag + user_sync_enabled set); fixed by upstream commit ca5d89812015ef2db3acc62826f73650450b331e |
| Language / Platform | Python (exploit script, using uv/toml/requests); target is Go-based Grafana Enterprise, test stand via Docker Compose |
| Authentication Required | Yes — requires a valid Grafana service-account Bearer token with SCIM API access |
| Network Access Required | Yes (HTTP/HTTPS to the Grafana Enterprise SCIM API) |
Summary
Grafana Enterprise/Cloud’s SCIM provisioning feature (enabled via the enableSCIM feature flag together with user_sync_enabled) fails to properly validate the externalId supplied when a SCIM client creates a user via POST /api/scim/v2/Users. This lets a caller with SCIM API access overwrite or collide with the internal ID of an existing Grafana user, effectively allowing the newly-provisioned SCIM identity to take over/impersonate that internal user — leading to privilege escalation (e.g. impersonating an existing Admin account). The repository ships a Docker Compose “stand” that spins up a real Grafana Enterprise instance with SCIM enabled (requiring a valid Enterprise license) plus a small Python exploit that posts a crafted SCIM user-creation payload with a chosen externalId targeting the victim’s internal user ID. The upstream fix adds explicit checks preventing this ID collision during SCIM user provisioning.
Vulnerability Details
Root Cause
When SCIM provisioning is enabled (auth.scim config with user_sync_enabled = true), Grafana’s SCIM user-creation endpoint accepted an attacker/client-supplied externalId without verifying it doesn’t collide with the internal ID of a pre-existing (non-SCIM) user. Because Grafana links SCIM-provisioned identities to internal user records via this ID, a crafted externalId matching a victim’s internal ID lets the SCIM-created identity assume/override that user’s identity:
| |
The upstream fix (commit ca5d89812015ef2db3acc62826f73650450b331e) adds checks to reject SCIM user-provisioning requests whose externalId would collide with an existing internal user ID.
Attack Vector
- Target Grafana Enterprise/Cloud instance has SCIM provisioning enabled (
enableSCIMfeature flag) anduser_sync_enabled = true, withreject_non_provisioned_userstypicallyfalse. - Attacker obtains (or is issued) a service-account Bearer token with access to the SCIM API (e.g. via
POST /api/serviceaccounts+/tokens, as shown in the stand’sinit.sh). - Attacker identifies the internal user ID (
uid) of a victim account they wish to impersonate (e.g. an existing Admin). - Attacker sends
POST /api/scim/v2/Userswith a SCIM user payload whoseexternalIdis set to the victim’s internaluid, anduserName/emailsset to an attacker-controlled account name. - Due to the missing collision check, Grafana’s SCIM sync links the newly created SCIM identity to the victim’s internal user record, allowing the attacker’s SCIM-managed account to impersonate or assume the privileges of the victim’s account.
Impact
An attacker with SCIM API access (service-account token) can impersonate an existing Grafana user — including administrators — resulting in privilege escalation and unauthorized access to dashboards, data sources, and administrative functions within the affected Grafana Enterprise/Cloud organization.
Environment / Lab Setup
Target (stand):
- Docker Compose stack running grafana/grafana-enterprise:12.0
- Valid Grafana Enterprise license key placed at ./stand/license.jwt
- grafana.ini: [auth.scim] user_sync_enabled = true, group_sync_enabled = true,
reject_non_provisioned_users = false; [enterprise] license_path = /secrets/license.jwt
- stand/init.sh creates an Admin-role service account and prints its API token
Attacker:
- Python 3 with `uv` (or pip) + `requests`, `toml`
- exploit/resource/config.toml populated with the service-account token,
victim account/uid, and target URL
Proof of Concept
PoC Script
See
exploit/src/main.py,exploit/resource/config.toml, and thestand/Docker Compose test bed in this folder.
| |
Detection & Indicators of Compromise
Signs of compromise:
- New SCIM-provisioned user records whose
externalIdmatches an existing user’s internal ID - Unexpected changes in ownership/permissions on an existing (especially Admin) account
- Service-account tokens with SCIM API scope used outside of the expected IdP-sync process
- Audit log entries showing SCIM user creation/updates that do not correspond to the configured identity provider’s sync jobs
Remediation
| Action | Detail |
|---|---|
| Primary fix | Upgrade Grafana Enterprise to a version including commit ca5d89812015ef2db3acc62826f73650450b331e, which adds validation preventing SCIM externalId collisions with existing internal user IDs |
| Interim mitigation | Restrict issuance of SCIM-scoped service-account tokens to trusted automation only; set reject_non_provisioned_users = true where feasible; monitor SCIM user-provisioning requests for externalId values matching existing user IDs |
References
- Source repository
- NIST NVD - CVE-2025-41115
- Grafana security advisory (blog)
- GitLab Advisory Database entry
- Doyensec - SCIM Hunting (background on SCIM security issues)
Notes
Mirrored from https://github.com/I3r1h0n/GrafanaSCIMalform on 2026-07-06. Contains an exploit/ directory (Python project managed via uv) plus a stand/ Docker Compose test bed reproducing the Grafana SCIM flaw with a real Grafana Enterprise image; the stand requires a valid Grafana Enterprise license (license.jwt) to actually enable SCIM. Note: as shipped, exploit/src/main.py’s main() calls sys.exit(1) immediately after logging “Exploit started” and before it loads config.toml or calls exploit() — the exploit logic itself is intact and functional if that early exit is removed, but the script does not run the actual POST request out of the box.