chore(deps): update dependency @better-auth/oauth-provider to v1.6.5 [security]#20
Open
renovate[bot] wants to merge 1 commit intomainfrom
Open
Conversation
…[security] | datasource | package | from | to | | ---------- | --------------------------- | ----- | ----- | | npm | @better-auth/oauth-provider | 1.6.0 | 1.6.5 |
Dependency Review✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This PR contains the following updates:
1.6.0→1.6.5OAuth 2.1 Provider: Unprivileged users can register OAuth clients
GHSA-xr8f-h2gw-9xh6
More information
Details
Summary
An authorization bypass in the OAuth provider allows any authenticated low-privilege user to create OAuth clients even when the deployment configures clientPrivileges to restrict client creation. The option contract explicitly includes a create action, but the create paths never invoke that callback, so applications that rely on clientPrivileges for RBAC can be silently misconfigured into allowing unauthorized client registration.
Details
The OAuth provider exposes a clientPrivileges authorization hook whose documented action set includes create:
https://github.com/better-auth/better-auth/blob/c5066fe5d68babf2376cfc63d813de5542eca463/packages/oauth-provider/src/types/index.ts#L209-L214
However, the two client-creation entry points for the adminCreateOAuthClient and the createOAuthClient, both delegate directly to createOAuthClientEndpoint without performing a clientPrivileges check.
In contrast, the non-create operations do enforce clientPrivileges in getClientEndpoint, getClientsEndpoint, deleteClientEndpoint, updateClientEndpoint and rotateClientSecretEndpoint. Those paths call the hook with read, list, delete, update, and rotate, but there is no corresponding create authorization check before persisting a new oauthClient record.
As a result, an application may reasonably configure clientPrivileges to allow only certain users or roles to manage OAuth clients, while any ordinary authenticated user can still call the create-client route successfully. This breaks the documented security boundary and enables unauthorized creation of OAuth clients with attacker-controlled redirect URIs and metadata.
If the server-only adminCreateOAuthClient endpoint is accidentally exposed to low-privilege authenticated users, an attacker can create OAuth clients with skip_consent enabled, which may allow silent consent bypass for that client and increases phishing and token-abuse risk.
PoC
Use the following setup to reproduce the authorization bypass in a minimal environment.
Server configuration example:
Sign up forbidden user:
Sign in with forbidden user (save cookies to txt file):
Attempt unauthorized client creation as forbidden user:
Expected result:
HTTP 401 Unauthorized, because clientPrivileges denies create for forbidden@test.com.
Actual result:
Client is created successfully (HTTP 200 with client_id and client_secret), demonstrating that create authorization is not enforced through clientPrivileges on this path.
Optional high-impact variant (only if server-only endpoint is exposed by deployment):
Call the admin create endpoint and set skip_consent true to create a client that may bypass user consent flow for that client.
Impact
This is an authorization bypass (broken access control / RBAC enforcement gap) affecting applications that use oauth-provider and rely on clientPrivileges to restrict who can register OAuth clients.
Potential impact includes:
Severity is deployment-dependent, but security-relevant by default because a documented access-control hook is bypassed for client creation.
Severity
CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:L/VI:H/VA:N/SC:L/SI:H/SA:NReferences
This data is provided by OSV and the GitHub Advisory Database (CC-BY 4.0).
Release Notes
better-auth/better-auth (@better-auth/oauth-provider)
v1.6.5Compare Source
Patch Changes
5b900a2Thanks @chdanielmueller! - fix(oauth-provider): enforce client privilege checks on OAuth client creationUpdated dependencies [
938dd80,0538627]:v1.6.4Compare Source
Patch Changes
9aed910,acbd6ef,39d6af2]:v1.6.3Compare Source
Patch Changes
#9123
e2e25a4Thanks @gustavovalverde! - fix(oauth-provider): override confidential auth methods to public in unauthenticated DCRWhen
allowUnauthenticatedClientRegistrationis enabled, unauthenticated DCRrequests that specify
client_secret_post,client_secret_basic, or omittoken_endpoint_auth_method(which defaults toclient_secret_basicperRFC 7591 §2) are
now silently overridden to
token_endpoint_auth_method: "none"(public client)instead of being rejected with HTTP 401.
This follows RFC 7591 §3.2.1,
which allows the server to "reject or replace any of the client's requested
metadata values submitted during the registration and substitute them with
suitable values." The registration response communicates the actual method
back to the client, allowing compliant clients to adjust.
This fixes interoperability with real-world MCP clients (Claude, Codex, Factory
Droid, and others) that send
token_endpoint_auth_method: "client_secret_post"in their DCR payload because the server metadata advertises it in
token_endpoint_auth_methods_supported.Closes #8588
#9131
5142e9cThanks @gustavovalverde! - harden dynamicbaseURLhandling for directauth.api.*calls and plugin metadata helpersDirect
auth.api.*callsAPIErrorwith a clear message when the baseURL can't be resolved (no source and nofallback), instead of leavingctx.context.baseURL = ""for downstream plugins to crash on.allowedHostsmismatches on the direct-API path toAPIError.advanced.trustedProxyHeaderson the dynamic path (defaulttrue, unchanged). Previouslyx-forwarded-host/-protowere unconditionally trusted withallowedHosts; they now go through the same gate as the static path. The default flip tofalseships in a follow-up PR.resolveRequestContextrehydratestrustedProvidersand cookies per call (in addition totrustedOrigins). User-definedtrustedOrigins(req)/trustedProviders(req)callbacks receive aRequestsynthesized from forwarded headers when no fullRequestis available.httpfor loopback hosts (localhost,127.0.0.1,[::1],0.0.0.0) on the headers-only protocol fallback, so local-dev calls don't silently resolve tohttps://localhost:3000.hasRequestusesisRequestLike, which now rejects objects that spoofSymbol.toStringTagwithout a realurl/headers.getshape.Plugin metadata helpers
oauthProviderAuthServerMetadata,oauthProviderOpenIdConfigMetadata,oAuthDiscoveryMetadata, andoAuthProtectedResourceMetadataforward the incoming request to their chainedauth.apicalls, soissuerand discovery URLs reflect the request host on dynamic configs.withMcpAuthforwards the incoming request togetMcpSession, threadstrustedProxyHeaders, and emits a bareBearerchallenge whenbaseURLcan't be resolved (instead ofBearer resource_metadata="undefined/...").metadataResponsein@better-auth/oauth-providernormalizes headers vianew Headers()so callers can passHeaders, tuple arrays, or records without silently dropping entries.#9118
314e06fThanks @gustavovalverde! - feat(oauth-provider): addcustomTokenResponseFieldscallback and Zod validation for authorization codesAdd
customTokenResponseFieldscallback toOAuthOptionsfor injecting custom fields into token endpoint responses across all grant types. Standard OAuth fields (access_token,token_type, etc.) cannot be overridden. Follows the same pattern ascustomAccessTokenClaimsandcustomIdTokenClaims.Authorization code verification values are now validated with a Zod schema at deserialization, consistently returning
invalid_verificationerrors for malformed or corrupted values instead of potential 500s.Updated dependencies [
5142e9c,484ce6a,f875897,6ce30cf,f6428d0,9a6d475,513dabb,c5066fe,5f84335]:v1.6.2Compare Source
Patch Changes
#9060
4c829bfThanks @gustavovalverde! - fix(oauth-provider): preserve multi-valued query params through prompt redirectsserializeAuthorizationQuerynow usesparams.append()for array values instead ofString(array)which collapsed them into a single comma-joined entry.deleteFromPromptreturn type widens fromRecord<string, string>toRecord<string, string | string[]>. The previous type was incorrect —Object.fromEntries()silently dropped duplicate keys, so the narrower type only held because the data was being corrupted.#8998
c6922dcThanks @dvanmali! - Typescript specifies skip_consent type never and errors through zodUpdated dependencies [
9deb793,2cbcb9b,b20fa42,608d8c3,8409843,e78a7b1]:v1.6.1Compare Source
Patch Changes
2e537df,f61ad1c,7495830]:Configuration
📅 Schedule: (in timezone America/New_York)
🚦 Automerge: Disabled by config. Please merge this manually once you are satisfied.
♻ Rebasing: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.
🔕 Ignore: Close this PR and you won't be reminded about this update again.
This PR was generated by Mend Renovate. View the repository job log.