CVE-2026-67331
better-auth SCIM 1.5.0 before 1.7.0-beta.4 Authorization Bypass
better-auth SCIM versions from 1.5.0 before 1.7.0-beta.4 fail to bind non-organization SCIM providers to their creator by default, allowing authenticated users to manage other users' providers. Attackers can regenerate SCIM bearer tokens, invalidate legitimate tokens, and authenticate to SCIM API routes with the attacker-controlled token.
Attack profile
How easy it is to exploit
- Attack vector
- Network
- Complexity
- Low
- Privileges needed
- Low
- User interaction
- None
What an attacker can affect
- Confidentiality
- High
- Integrity
- High
- Availability
- Low
Exploit likelihood
What each source reports
CVE List Score used
8.7
better-auth SCIM 1.5.0 before 1.7.0-beta.4 Authorization Bypass
better-auth SCIM versions from 1.5.0 before 1.7.0-beta.4 fail to bind non-organization SCIM providers to their creator by default, allowing authenticated users to manage other users' providers. Attackers can regenerate SCIM bearer tokens, invalidate legitimate tokens, and authenticate to SCIM API routes with the attacker-controlled token.
- Record
CVE-2026-67331- CVSS 4.0
- 8.7 High
CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:H/VA:L/SC:N/SI:N/SA:N - CVSS 3.1
- 8.3 High
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:L - Weakness
- CWE-639
- Updated
- 2026-11-02
EUVDEUVD-2026-51846
8.7
better-auth SCIM versions from 1.5.0 before 1.7.0-beta.4 fail to bind non-organization SCIM providers to their creator by default, allowing authenticated users to manage other users' providers. Attackers can regenerate SCIM bearer tokens, invalidate legitimate tokens, and authenticate to SCIM API routes with the attacker-controlled token.
- Record
EUVD-2026-51846- CVSS 4.0
- 8.7 High
CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:H/VA:L/SC:N/SI:N/SA:N - Updated
- 2026-11-02
GitHub AdvisoriesGHSA-gj37-5j8h-j367
8.7
better-auth SCIM versions from 1.5.0 before 1.7.0-beta.4 fail to bind non-organization SCIM...
better-auth SCIM versions from 1.5.0 before 1.7.0-beta.4 fail to bind non-organization SCIM providers to their creator by default, allowing authenticated users to manage other users' providers. Attackers can regenerate SCIM bearer tokens, invalidate legitimate tokens, and authenticate to SCIM API routes with the attacker-controlled token.
- Record
GHSA-gj37-5j8h-j367- CVSS 4.0
- 8.7 High
CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:H/VA:L/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X - CVSS 3.1
- 8.3 High
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:L - Weakness
- CWE-639
- Updated
- 2026-11-02
GitHub AdvisoriesGHSA-j8v8-g9cx-5qf4
8.3
@better-auth/scim: Account/provider takeover via missing owner binding on non-org SCIM providers
Am I affected?
Users are affected if all of these hold:
- They install and register the
@better-auth/scimplugin (plugins: [scim()]). - They create SCIM providers without an
organizationId, that is, non-organization ("personal") providers. Organization-scoped providers are not affected because they enforce organization membership and role. - Their application's deployment has more than one authenticated user, so one account can target another user's provider.
- They have not set
providerOwnership: { enabled: true }.
The SCIM management endpoints first shipped in 1.5.0, so every stable release from 1.5.0 onward is affected, and the stable line is not patched. On the pre-release line, builds through 1.7.0-beta.3 are affected, and 1.7.0-beta.4 carries the fix.
Fix:
- Upgrade to
@better-auth/[email protected](then1.7.0). This is a breaking change: it removes theproviderOwnershipoption, makes owner binding mandatory, and adds a permanentscimProvider.userIdcolumn. - Run the schema migration after upgrading (
npx auth migrate). Connections created before the upgrade carry no owner and become unreachable through the management endpoints, so reclaim them at the database level. - The
1.6.xstable line is not patched. If developers stay on it, apply the workaround below.
Summary
@better-auth/scim does not bind non-organization SCIM providers to their creator in the default configuration. Any authenticated user can manage another user's non-org provider, including reading its metadata, listing connections, regenerating its SCIM bearer token, and deleting the connection. Regenerating the token rotates it: the legitimate token stops working and the attacker holds a valid one.
Details
The plugin tracks provider ownership through an opt-in providerOwnership option and a scimProvider.userId column. Both default to off. When ownership is disabled, a non-org provider row is created without a userId, and the management access check denies access only when a stored owner id is present and differs from the caller:
// non-organization branch of the access check
} else if (provider.userId && provider.userId !== userId) {
throw new APIError("FORBIDDEN", { message: "You must be the owner to access this provider" });
}
Because the default row has no userId, the condition is false and the request is allowed. The same gap reaches every management operation: token generation and regeneration, single-provider read, the connection list (which returns providers where p.userId === userId || !p.userId), and provider deletion.
The most sensitive operation is token regeneration. If Alice creates a non-org provider corp-idp, Bob can call the same generate-token endpoint with providerId: "corp-idp". The existing row passes the ownerless access check, so the plugin deletes it, creates a fresh row, and returns a new SCIM bearer token to Bob. Alice's previous token is now invalid, and Bob's token authenticates against that provider's SCIM API routes.
This requires no organization membership and no elevated role. It is reachable in the default scim() configuration whenever non-organization providers are used.
Proof of concept
Two authenticated users, Alice and Bob, in a default scim() setup:
- Alice signs in and creates a non-org provider:
POST /scim/generate-tokenwith{ "providerId": "corp-idp" }. - Bob signs in and reads Alice's provider:
GET /scim/get-provider-connection?providerId=corp-idpreturns200with{ "providerId": "corp-idp" }. - Bob regenerates the token:
POST /scim/generate-tokenwith{ "providerId": "corp-idp" }returns201and a newscimToken. - Alice's old token is rejected at
GET /scim/v2/Users(401); Bob's regenerated token is accepted (200).
The behavior is reproducible through Better Auth's public API surface with two distinct sessions.
Patches
Fixed in @better-auth/[email protected] (then 1.7.0). The fix…
- Record
GHSA-j8v8-g9cx-5qf4- CVSS 3.1
- 8.3 High
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:L - Weakness
- CWE-639, CWE-862
- Updated
- 2026-11-02
NVD
8.7
better-auth SCIM versions from 1.5.0 before 1.7.0-beta.4 fail to bind non-organization SCIM providers to their creator by default, allowing authenticated users to manage other users' providers. Attackers can regenerate SCIM bearer tokens, invalidate legitimate tokens, and authenticate to SCIM API routes with the attacker-controlled token.
- Record
CVE-2026-67331- CVSS 4.0
- 8.7 High
CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:H/VA:L/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X - CVSS 3.1
- 8.3 High
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:L - Weakness
- CWE-639
- Updated
- 2026-11-02
OSV
8.7
better-auth SCIM 1.5.0 before 1.7.0-beta.4 Authorization Bypass
better-auth SCIM versions from 1.5.0 before 1.7.0-beta.4 fail to bind non-organization SCIM providers to their creator by default, allowing authenticated users to manage other users' providers. Attackers can regenerate SCIM bearer tokens, invalidate legitimate tokens, and authenticate to SCIM API routes with the attacker-controlled token.
- Record
CVE-2026-67331- CVSS 4.0
- 8.7 High
CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:H/VA:L/SC:N/SI:N/SA:N - Weakness
- CWE-639
- Updated
- 2026-11-02
OSVGHSA-j8v8-g9cx-5qf4
8.3
@better-auth/scim: Account/provider takeover via missing owner binding on non-org SCIM providers
Am I affected?
Users are affected if all of these hold:
- They install and register the
@better-auth/scimplugin (plugins: [scim()]). - They create SCIM providers without an
organizationId, that is, non-organization ("personal") providers. Organization-scoped providers are not affected because they enforce organization membership and role. - Their application's deployment has more than one authenticated user, so one account can target another user's provider.
- They have not set
providerOwnership: { enabled: true }.
The SCIM management endpoints first shipped in 1.5.0, so every stable release from 1.5.0 onward is affected, and the stable line is not patched. On the pre-release line, builds through 1.7.0-beta.3 are affected, and 1.7.0-beta.4 carries the fix.
Fix:
- Upgrade to
@better-auth/[email protected](then1.7.0). This is a breaking change: it removes theproviderOwnershipoption, makes owner binding mandatory, and adds a permanentscimProvider.userIdcolumn. - Run the schema migration after upgrading (
npx auth migrate). Connections created before the upgrade carry no owner and become unreachable through the management endpoints, so reclaim them at the database level. - The
1.6.xstable line is not patched. If developers stay on it, apply the workaround below.
Summary
@better-auth/scim does not bind non-organization SCIM providers to their creator in the default configuration. Any authenticated user can manage another user's non-org provider, including reading its metadata, listing connections, regenerating its SCIM bearer token, and deleting the connection. Regenerating the token rotates it: the legitimate token stops working and the attacker holds a valid one.
Details
The plugin tracks provider ownership through an opt-in providerOwnership option and a scimProvider.userId column. Both default to off. When ownership is disabled, a non-org provider row is created without a userId, and the management access check denies access only when a stored owner id is present and differs from the caller:
// non-organization branch of the access check
} else if (provider.userId && provider.userId !== userId) {
throw new APIError("FORBIDDEN", { message: "You must be the owner to access this provider" });
}
Because the default row has no userId, the condition is false and the request is allowed. The same gap reaches every management operation: token generation and regeneration, single-provider read, the connection list (which returns providers where p.userId === userId || !p.userId), and provider deletion.
The most sensitive operation is token regeneration. If Alice creates a non-org provider corp-idp, Bob can call the same generate-token endpoint with providerId: "corp-idp". The existing row passes the ownerless access check, so the plugin deletes it, creates a fresh row, and returns a new SCIM bearer token to Bob. Alice's previous token is now invalid, and Bob's token authenticates against that provider's SCIM API routes.
This requires no organization membership and no elevated role. It is reachable in the default scim() configuration whenever non-organization providers are used.
Proof of concept
Two authenticated users, Alice and Bob, in a default scim() setup:
- Alice signs in and creates a non-org provider:
POST /scim/generate-tokenwith{ "providerId": "corp-idp" }. - Bob signs in and reads Alice's provider:
GET /scim/get-provider-connection?providerId=corp-idpreturns200with{ "providerId": "corp-idp" }. - Bob regenerates the token:
POST /scim/generate-tokenwith{ "providerId": "corp-idp" }returns201and a newscimToken. - Alice's old token is rejected at
GET /scim/v2/Users(401); Bob's regenerated token is accepted (200).
The behavior is reproducible through Better Auth's public API surface with two distinct sessions.
Patches
Fixed in @better-auth/[email protected] (then 1.7.0). The fix…
- Record
GHSA-j8v8-g9cx-5qf4- CVSS 3.1
- 8.3 High
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:L - Weakness
- CWE-639, CWE-862
- Updated
- 2026-11-02
Affected products
Affected packages
| Package | Affected | Fixed |
|---|---|---|
@better-auth/scimnpm |
1.5.0 up to 1.7.0-beta.4 | 1.7.0-beta.4 |
History
| Recorded | Changed | Sources |
|---|---|---|
| first indexed | CVE List, EUVD, GitHub Advisories, NVD, OSV |
Dates are when Every CVE recorded each change. Upstream dates may differ.
In short
CVE-2026-67331 is a high vulnerability (CVSS 8.7) in Better-auth Scim, published July 7, 2026. No source lists public exploit code. EPSS puts the chance of exploitation in the next 30 days at 0.39%, the 33rd percentile. Fixed in @better-auth/scim 1.7.0-beta.4.
References
github.com/better-auth/better-auth/security/advisories/GHSA-j8v8-g9cx-5qf4
vulncheck.com/advisories/better-auth-scim-before-beta-4-authorization-bypass
nvd.nist.gov/vuln/detail/CVE-2026-67331
github.com/advisories/GHSA-gj37-5j8h-j367
github.com/better-auth/better-auth/releases/tag/v1.7.0-beta.4
github.com/advisories/GHSA-j8v8-g9cx-5qf4
github.com/CVEProject/cvelistV5/tree/main/cves/2026/67xxx/CVE-2026-67331.json
github.com/better-auth/better-auth
Left out here: the rest of 2 source descriptions. The JSON record has them.