doorkeeper-openid_connect CVE-2026-44476
MEDIUMLifecycle Timeline
2DescriptionCVE.org
Impact
The DynamicClientRegistrationController#register action hard-codes confidential: false when creating applications (dynamic_client_registration_controller.rb:18-25), yet the response includes a client_secret and advertises token_endpoint_auth_methods_supported: ["client_secret_basic", "client_secret_post"].
Because Doorkeeper's Application.by_uid_and_secret treats a blank/missing secret as valid for non-confidential (public) clients, an attacker who knows only the client_id (which is public information) can authenticate as the dynamically-registered client at the token endpoint.
Note that Dynamic Client Registration is opt-in feature which is disabled by default so only projects that explicitly enabled it are affected.
Steps to Reproduce
- Enable dynamic client registration in the initializer
- POST /oauth/registration with client_name, redirect_uris, and scope
- Observe: response returns client_secret, but the created
Doorkeeper::Application has confidential: false
- Call
Doorkeeper::Application.by_uid_and_secret(client_id, nil)- it
returns the application (credentials bypass)
- POST /oauth/token with grant_type=client_credentials and only
client_id (no client_secret) - the token endpoint issues an access token without any secret verification
Patches
Patched in 1.10.0
Workarounds
Upgrade existing applications created with a Dynamic Client registration to have confidential: true
AnalysisAI
Authentication bypass in doorkeeper-openid_connect's Dynamic Client Registration feature allows any party with a known client_id to obtain OAuth access tokens without supplying a client_secret. The root defect is in DynamicClientRegistrationController#register (dynamic_client_registration_controller.rb:18-25), which hard-codes confidential: false on every dynamically registered application while simultaneously returning a client_secret in the response and advertising client_secret_basic/client_secret_post auth methods. Because Doorkeeper's Application.by_uid_and_secret accepts a nil secret as valid for public (non-confidential) clients, the secret returned at registration is functionally decorative - any caller can authenticate at the token endpoint using only the public client_id. No public exploit code has been identified at time of analysis, and no CISA KEV listing exists, but the advisory includes verbatim reproduction steps that document the bypass in full detail.
Technical ContextAI
doorkeeper-openid_connect is a Ruby gem (pkg:rubygems/doorkeeper-openid_connect) that extends the Doorkeeper OAuth 2.0 provider with OpenID Connect support, including an optional Dynamic Client Registration endpoint conforming to RFC 7591. The vulnerability arises from a mismatch between the OAuth application's confidential flag and the authentication methods advertised and returned to registering clients. In Doorkeeper's data model, confidential: false designates a 'public' client - browsers, native apps - for which the framework intentionally permits by_uid_and_secret(uid, nil) to return a valid application record, since public clients cannot securely store secrets. The Dynamic Client Registration controller incorrectly applies this public-client designation to every dynamically registered application regardless of the requested token_endpoint_auth_method, while simultaneously generating and returning a client_secret. The result is a credential that appears valid but is never enforced. CWE-290 (Authentication Bypass by Spoofing) captures this precisely: the system issues credentials that it then fails to verify, allowing an attacker to impersonate a legitimate registered client using only its public identifier.
RemediationAI
The primary remediation is to upgrade doorkeeper-openid_connect to version 1.10.0, which is the vendor-confirmed patched release per GHSA-m6vc-f87m-cc2h and the v1.10.0 release notes. The fix in 1.10.0 (change #263) correctly derives the confidential flag from the token_endpoint_auth_method requested at registration per RFC 7591: clients requesting client_secret_basic (the new default) are created as confidential; clients requesting none are created as public; unsupported methods such as private_key_jwt are rejected with invalid_client_metadata. For deployments that cannot immediately upgrade, the vendor-documented workaround is to update all existing Doorkeeper::Application records that were created via Dynamic Client Registration to set confidential: true - this can be accomplished with a targeted Rails migration or console command (Doorkeeper::Application.where(dcr_created: true).update_all(confidential: true), adjusting the filter condition to match however DCR-registered apps are identified in the local schema). Note that toggling existing applications to confidential will begin enforcing secret verification, which may break any legitimate clients that were relying on the unenforced credential behavior. As an additional compensating control, temporarily disabling the Dynamic Client Registration endpoint in the initializer (by removing the enable_dynamic_client_registration configuration) will prevent new vulnerable registrations while a patch is staged.
Same weakness CWE-290 – Authentication Bypass by Spoofing
View allSame technique Authentication Bypass
View allShare
External POC / Exploit Code
Leaving vuln.today
GHSA-m6vc-f87m-cc2h