CVE-2026-116672: Oterm · Authlib RFC 7592 examples omit registration-access-token client binding
Affects otermSource GCVE Database
Not known to be exploited · CVSS 8.8 High : upgrade to 0.26.1 soon.
Data as of 31 Oct 2026, 16:51 UTC
Thin evidence
One scorer or none| CNA (GitHub_M) | CVSS 3.1 | 8.8 |
|---|
- Patch
- Available – fixed in 0.26.1
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:HExploitation evidence
Disclosed: evidence found.
CVE published 27 Oct 2026
Detectable: no evidence on record.
No public nuclei template indexed
Weaponized: no evidence on record.
No public exploit code indexed in Metasploit or Exploit-DB
Exploited in the wildExploited: no evidence on record.
Not in CISA KEV and no source reports exploitation
Observed by OffSeq MirageSeen by Mirage: no evidence on record.
No attack traffic recorded by OffSeq Mirage sensors
A missing step is not evidence of safety. Sources: cve.org (opens in a new tab), the Metasploit, Exploit-DB and nuclei-templates index as of 30 Oct 2026.
What to do
Upgrade oterm to 0.26.1.
Affected software
| Product | Affected | Fixed in |
|---|---|---|
Homebrewotermpkg:brew/otermOther threats | Affected
| Fixed in
|
Check your own hosts for these packages with threat-finder (opens in a new tab), our free open-source scanner.
Description
## Description ### Summary RFC 7592 (OAuth 2.0 Dynamic Client Registration Management Protocol) lets a previously registered client read, update, or delete its own registration, authenticated by a `registration_access_token` issued specifically to that client at registration time. The entire security model of this protocol depends on the server verifying that the token presented in the request actually belongs to the client identified in the request, not merely that the token is valid for some client. Authlib's `ClientConfigurationEndpoint` implements the control flow correctly in structure, calling `authenticate_token`, then `authenticate_client`, then `check_permission`, and treats all three as abstract methods that "Developers MUST implement in subclass." The problem is that the documented example implementations for these methods, taken together exactly as written, never perform the one check that matters: binding the authenticated token to the specific client being accessed. A developer who implements these methods by following the provided examples ends up with a complete authorization bypass on this endpoint. ### Details `authenticate_client`'s documented example (`authlib/oauth2/rfc7592/endpoint.py`): ```python def authenticate_client(self, request): """Read a client from the request payload. Developers MUST implement this method in subclass:: def authenticate_client(self, request): client_id = request.payload.data.get("client_id") return Client.get(client_id=client_id) :return: client instance """ raise NotImplementedError() ``` This looks the target client up purely by the `client_id` supplied in the request payload, with no reference to the token at all. `check_permission`'s documented example, in the same file: ```python def check_permission(self, client, request): """Checks whether the current client is allowed to be accessed, edited or deleted. Developers MUST implement it in subclass, e.g.:: def check_permission(self, client, request): return client.editable :return: boolean """ raise NotImplementedError() ``` This checks a property of the target client alone (whether it is generally "editable"), again with no reference to `request.credential`, the authenticated token object returned earlier by `authenticate_token` and stored on the request specifically so that later steps can check it: ```python def create_configuration_response(self, request): token = self.authenticate_token(request) if not token: raise AccessDeniedError() request.credential = token client = self.authenticate_client(request) ... if not self.check_permission(client, request): raise UnauthorizedClientError(...) ``` `request.credential` is set specifically so that a binding check can be performed downstream, but neither documented example ever reads it. Following both examples as written produces an implementation where the only requirements to access, modify, or delete a client's registration are: possessing any valid registration_access_token for any client, and knowing or guessing the target `client_id`. This is meaningfully different from how the equivalent example is written for the token introspection endpoint (RFC 7662) elsewhere in the same codebase, which does correctly demonstrate checking the authenticated caller's own identity (`authlib/oauth2/rfc7662/introspection.py`): ```python def check_permission(self, token, client, request): """Check if the request has permission to introspect the token. Developers MUST implement this method:: def check_permission(self, token, client, request): # only allow a special client to introspect the token return client.client_id == "introspection_client" """ ``` In that endpoint, `client` represents the already-authenticated caller (verified through normal client credential authentication earlier in the flow), so checking a property of `client` is meaningful authorization logic. In the RFC 7592 endpoint, `client` instead represents the target being acted upon, not the caller, so the same style of example is actively misleading: it looks like a reasonable authorization check but performs none of the binding the protocol requires. No file anywhere in the repository, including the Flask, Django, and SQLAlchemy integration modules, provides a complete, corrected reference implementation of `ClientConfigurationEndpoint`. The misleading docstring examples are the only guidance shipped for this endpoint. ### Realistic exploitability RFC 7591 dynamic client registration is commonly deployed without requiring an initial access token, since the specification explicitly anticipates open, self-service registration as a normal deployment model. Under that common configuration, an attacker can freely self-register their own throwaway client with no authentication at all, receive a valid `registratio
References
- github.com/authlib/authlib/security/advisories/GHSA-c73q-w75p-j82v (opens in a new tab)
- nvd.nist.gov/vuln/detail/CVE-2026-116672 (opens in a new tab)
- github.com/authlib/authlib/commit/1bd2a313492ce0a4d0571c150730907aa3fc91ff (opens in a new tab)
- github.com/authlib/authlib (opens in a new tab)
- github.com/authlib/authlib/releases/tag/v1.9.1 (opens in a new tab)