CVE-2026-118669
OAuthLib: Token grants can use attacker-supplied client_id for authorization after authenticating a different client
OAuthLib is an implementation of the OAuth request-signing logic for Python 3.6+. Prior to 4.0.0, the client_credentials and Resource Owner Password Credentials token grant handlers can authenticate request.client as one confidential client while retaining an attacker-supplied request.client_id for validate_grant_type and validate_scopes. A lower-privilege authenticated client can therefore cause grant and scope authorization to use another client's identity when an application validator relies on the documented client_id argument, potentially issuing tokens with unauthorized grants or scopes. Validators that authorize exclusively from request.client may not be affected. This issue is fixed in version 4.0.0.
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
- None
- Integrity
- High
- Availability
- None
Exploit likelihood
What each source reports
CVE List Score used
8.4
OAuthLib: Token grants can use attacker-supplied client_id for authorization after authenticating a different client
OAuthLib is an implementation of the OAuth request-signing logic for Python 3.6+. Prior to 4.0.0, the client_credentials and Resource Owner Password Credentials token grant handlers can authenticate request.client as one confidential client while retaining an attacker-supplied request.client_id for validate_grant_type and validate_scopes. A lower-privilege authenticated client can therefore cause grant and scope authorization to use another client's identity when an application validator relies on the documented client_id argument, potentially issuing tokens with unauthorized grants or scopes. Validators that authorize exclusively from request.client may not be affected. This issue is fixed in version 4.0.0.
- Record
CVE-2026-118669- CVSS 4.0
- 8.4 High
CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:N/VI:H/VA:N/SC:H/SI:H/SA:N - Weakness
- CWE-863
- Updated
- 2026-11-03
EUVDEUVD-2026-112488
8.4
OAuthLib is an implementation of the OAuth request-signing logic for Python 3.6+. Prior to 4.0.0, the client_credentials and Resource Owner Password Credentials token grant handlers can authenticate request.client as one confidential client while retaining an attacker-supplied request.client_id for validate_grant_type and validate_scopes. A lower-privilege authenticated client can therefore cause grant and scope authorization to use another client's identity when an application validator relies on the documented client_id argument, potentially issuing tokens with unauthorized grants or scopes. Validators that authorize exclusively from request.client may not be affected. This issue is fixed in version 4.0.0.
- Record
EUVD-2026-112488- CVSS 4.0
- 8.4 High
CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:N/VI:H/VA:N/SC:H/SI:H/SA:N - Updated
- 2026-11-03
GitHub AdvisoriesGHSA-7984-qgvg-3j9c
8.4
OAuthLib: Token grants can use attacker-supplied client_id for authorization after authenticating a different client
Summary
OAuthlib's token grant handlers can authenticate one client while authorizing the grant type and requested scopes using a different, attacker-supplied client_id from the request body.
In affected token grant flows, authenticate_client(request) sets request.client to the authenticated client object, but OAuthlib does not require request.client_id to match request.client.client_id. If the request body already contains client_id=..., OAuthlib keeps that value and passes it to validate_grant_type() and validate_scopes().
As a result, an authenticated low-privilege confidential client can authenticate as itself, submit another client's client_id in the token request body, and cause grant and scope validation to run under that other client identity.
Affected Surface
The affected public surface is the OAuth2 token endpoint handling for:
client_credentialspassword/ Resource Owner Password Credentials
The issue is relevant to OAuthlib provider deployments where:
- the attacker has credentials for one valid lower-privilege confidential client;
- another client has broader grants or scopes;
- the application validator uses the
client_idargument passed by OAuthlib invalidate_grant_type()orvalidate_scopes(), as theRequestValidatorAPI is designed to support.
Deployments whose validators ignore the client_id argument and authorize only from request.client may not be affected.
Details
Request parses query and body parameters into request attributes, including client_id:
The RequestValidator.authenticate_client() contract requires the integrator to authenticate the client and set request.client:
For the client_credentials grant, OAuthlib authenticates the client, verifies that request.client has a client_id, then performs grant and scope validation before normalizing request.client_id from request.client.client_id:
The problematic order is:
if not self.request_validator.authenticate_client(request):
...
elif not hasattr(request.client, 'client_id'):
...
self.validate_grant_type(request)
request.client_id = request.client_id or request.client.client_id
self.validate_scopes(request)
Because OAuthlib only fills request.client_id when it is missing, an attacker-supplied body value such as client_id=high survives even when request.client.client_id == "low".
The shared grant helper then authorizes using request.client_id, while passing the authenticated client object separately:
validate_grant_type(request.client_id, request.grant_type, request.client, request): https://github.com/oauthlib/oauthlib/blob/b3f9edffed6b370e3eb92721cea0da22ec7e18b9/oauthlib/oauth2/rfc6749/grant_types/base.py#L152-L162validate_scopes(request.client_id, request.scopes, request.client, request): https://github.com/oauthlib/oauthlib/blob/b3f9edffed6b370e3eb92721cea0da22ec7e18b9/oauthlib/oauth2/rfc6749/grant_types/base.py#L164-L176
The same identity split exists in the Resource Owner Password Credentials flow. After client authentication and user validation, OAuthlib validates the grant and scopes before replacing a missing request.client_id from request.client.client_id:
- https://github.com/oauthlib/oauthlib/blob/b3f9edffed6b370e3eb92721cea0da22ec7e18b9/oauthlib/oauth2/rfc6749/grant_types/resource_owner_password_credentials.py#L87-L97
- https://github.com/oauthlib/oauthlib/blob/b3f9edffed6b370e3eb92721cea0da22ec7e18b9/oauthlib/oauth2/rfc6749/grant_types/resource_owner_password_credentials.py#L178-L195
This creates an…
- Record
GHSA-7984-qgvg-3j9c- CVSS 4.0
- 8.4 High
CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:N/VI:H/VA:N/SC:H/SI:H/SA:N - Weakness
- CWE-863
- Updated
- 2026-11-02
NVD
8.4
OAuthLib is an implementation of the OAuth request-signing logic for Python 3.6+. Prior to 4.0.0, the client_credentials and Resource Owner Password Credentials token grant handlers can authenticate request.client as one confidential client while retaining an attacker-supplied request.client_id for validate_grant_type and validate_scopes. A lower-privilege authenticated client can therefore cause grant and scope authorization to use another client's identity when an application validator relies on the documented client_id argument, potentially issuing tokens with unauthorized grants or scopes. Validators that authorize exclusively from request.client may not be affected. This issue is fixed in version 4.0.0.
- Record
CVE-2026-118669- CVSS 4.0
- 8.4 High
CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:N/VI:H/VA:N/SC:H/SI:H/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 - Weakness
- CWE-863
- Updated
- 2026-11-03
OSV
8.4
OAuthLib: Token grants can use attacker-supplied client_id for authorization after authenticating a different client
OAuthLib is an implementation of the OAuth request-signing logic for Python 3.6+. Prior to 4.0.0, the client_credentials and Resource Owner Password Credentials token grant handlers can authenticate request.client as one confidential client while retaining an attacker-supplied request.client_id for validate_grant_type and validate_scopes. A lower-privilege authenticated client can therefore cause grant and scope authorization to use another client's identity when an application validator relies on the documented client_id argument, potentially issuing tokens with unauthorized grants or scopes. Validators that authorize exclusively from request.client may not be affected. This issue is fixed in version 4.0.0.
- Record
CVE-2026-118669- CVSS 4.0
- 8.4 High
CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:N/VI:H/VA:N/SC:H/SI:H/SA:N - Weakness
- CWE-863
- Updated
- 2026-11-07
OSVDEBIAN-CVE-2026-118669
8.4
OAuthLib is an implementation of the OAuth request-signing logic for Python 3.6+. Prior to 4.0.0, the client_credentials and Resource Owner Password Credentials token grant handlers can authenticate request.client as one confidential client while retaining an attacker-supplied request.client_id for validate_grant_type and validate_scopes. A lower-privilege authenticated client can therefore cause grant and scope authorization to use another client's identity when an application validator relies on the documented client_id argument, potentially issuing tokens with unauthorized grants or scopes. Validators that authorize exclusively from request.client may not be affected. This issue is fixed in version 4.0.0.
- Record
DEBIAN-CVE-2026-118669- CVSS 4.0
- 8.4 High
CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:N/VI:H/VA:N/SC:H/SI:H/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 - Updated
- 2026-11-04
Show 4 moreShow less
OSVGHSA-7984-qgvg-3j9c
8.4
OAuthLib: Token grants can use attacker-supplied client_id for authorization after authenticating a different client
Summary
OAuthlib's token grant handlers can authenticate one client while authorizing the grant type and requested scopes using a different, attacker-supplied client_id from the request body.
In affected token grant flows, authenticate_client(request) sets request.client to the authenticated client object, but OAuthlib does not require request.client_id to match request.client.client_id. If the request body already contains client_id=..., OAuthlib keeps that value and passes it to validate_grant_type() and validate_scopes().
As a result, an authenticated low-privilege confidential client can authenticate as itself, submit another client's client_id in the token request body, and cause grant and scope validation to run under that other client identity.
Affected Surface
The affected public surface is the OAuth2 token endpoint handling for:
client_credentialspassword/ Resource Owner Password Credentials
The issue is relevant to OAuthlib provider deployments where:
- the attacker has credentials for one valid lower-privilege confidential client;
- another client has broader grants or scopes;
- the application validator uses the
client_idargument passed by OAuthlib invalidate_grant_type()orvalidate_scopes(), as theRequestValidatorAPI is designed to support.
Deployments whose validators ignore the client_id argument and authorize only from request.client may not be affected.
Details
Request parses query and body parameters into request attributes, including client_id:
The RequestValidator.authenticate_client() contract requires the integrator to authenticate the client and set request.client:
For the client_credentials grant, OAuthlib authenticates the client, verifies that request.client has a client_id, then performs grant and scope validation before normalizing request.client_id from request.client.client_id:
The problematic order is:
if not self.request_validator.authenticate_client(request):
...
elif not hasattr(request.client, 'client_id'):
...
self.validate_grant_type(request)
request.client_id = request.client_id or request.client.client_id
self.validate_scopes(request)
Because OAuthlib only fills request.client_id when it is missing, an attacker-supplied body value such as client_id=high survives even when request.client.client_id == "low".
The shared grant helper then authorizes using request.client_id, while passing the authenticated client object separately:
validate_grant_type(request.client_id, request.grant_type, request.client, request): https://github.com/oauthlib/oauthlib/blob/b3f9edffed6b370e3eb92721cea0da22ec7e18b9/oauthlib/oauth2/rfc6749/grant_types/base.py#L152-L162validate_scopes(request.client_id, request.scopes, request.client, request): https://github.com/oauthlib/oauthlib/blob/b3f9edffed6b370e3eb92721cea0da22ec7e18b9/oauthlib/oauth2/rfc6749/grant_types/base.py#L164-L176
The same identity split exists in the Resource Owner Password Credentials flow. After client authentication and user validation, OAuthlib validates the grant and scopes before replacing a missing request.client_id from request.client.client_id:
- https://github.com/oauthlib/oauthlib/blob/b3f9edffed6b370e3eb92721cea0da22ec7e18b9/oauthlib/oauth2/rfc6749/grant_types/resource_owner_password_credentials.py#L87-L97
- https://github.com/oauthlib/oauthlib/blob/b3f9edffed6b370e3eb92721cea0da22ec7e18b9/oauthlib/oauth2/rfc6749/grant_types/resource_owner_password_credentials.py#L178-L195
This creates an…
- Record
GHSA-7984-qgvg-3j9c- CVSS 4.0
- 8.4 High
CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:N/VI:H/VA:N/SC:H/SI:H/SA:N - Weakness
- CWE-863
- Updated
- 2026-11-02
OSVROOT-APP-PYPI-CVE-2026-118669
8.4
CVE-2026-118669 in oauthlib - Patched by Root
Root has patched CVE-2026-118669 in the oauthlib package for Root:PyPI. Multiple fixed versions available.
- Record
ROOT-APP-PYPI-CVE-2026-118669- CVSS 4.0
- 8.4 High
CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:N/VI:H/VA:N/SC:H/SI:H/SA:N - Updated
- 2026-11-06
OSVUBUNTU-CVE-2026-118669
8.4
OAuthLib is an implementation of the OAuth request-signing logic for Python 3.6+. Prior to 4.0.0, the client_credentials and Resource Owner Password Credentials token grant handlers can authenticate request.client as one confidential client while retaining an attacker-supplied request.client_id for validate_grant_type and validate_scopes. A lower-privilege authenticated client can therefore cause grant and scope authorization to use another client's identity when an application validator relies on the documented client_id argument, potentially issuing tokens with unauthorized grants or scopes. Validators that authorize exclusively from request.client may not be affected. This issue is fixed in version 4.0.0.
- Record
UBUNTU-CVE-2026-118669- CVSS 4.0
- 8.4 High
CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:N/VI:H/VA:N/SC:H/SI:H/SA:N - Updated
- 2026-11-05
OSVAZL-112133 No score
CVE-2026-118669 affecting package python-oauthlib 3.2.2-4
OAuthLib is an implementation of the OAuth request-signing logic for Python 3.6+. Prior to 4.0.0, the client_credentials and Resource Owner Password Credentials token grant handlers can authenticate request.client as one confidential client while retaining an attacker-supplied request.client_id for validate_grant_type and validate_scopes. A lower-privilege authenticated client can therefore cause grant and scope authorization to use another client's identity when an application validator relies on the documented client_id argument, potentially issuing tokens with unauthorized grants or scopes. Validators that authorize exclusively from request.client may not be affected. This issue is fixed in version 4.0.0.
- Record
AZL-112133- Updated
- 2026-11-05
Affected products
Affected packages
| Package | Affected | Fixed |
|---|---|---|
oauthlibPyPI |
before 4.0.0 | 4.0.0 |
python-oauthlibAzure Linux:3 |
through 3.2.2-4 | None known |
python-oauthlibDebian:12 |
All versions, plus listed versions 3.2.2-13.2.2-23.2.2-33.2.2-43.3.1-13.3.1-2 |
None known |
python-oauthlibDebian:13 |
All versions, plus listed versions 3.2.2-33.2.2-43.3.1-13.3.1-2 |
None known |
python-oauthlibDebian:14 |
All versions, plus listed versions 3.2.2-33.2.2-43.3.1-13.3.1-2 |
None known |
oauthlibPyPI |
before 4.0.0, plus listed versions 0.0.10.0.20.1.00.1.10.1.2 Show 45 moreShow less0.1.30.3.00.3.20.3.30.3.40.3.50.3.60.3.70.3.80.4.00.4.10.4.20.5.00.5.10.6.00.6.10.6.20.6.30.7.00.7.10.7.21.0.01.0.11.0.21.0.31.1.01.1.11.1.22.0.02.0.12.0.22.0.32.0.42.0.52.0.62.0.72.1.03.0.03.0.13.0.23.1.03.1.13.2.03.2.13.2.2 |
4.0.0 |
oauthlibRoot:PyPI |
before 3.3.1+aikido.2 | 3.3.1+aikido.23.2.2+aikido.1 |
python-oauthlibUbuntu:16.04:LTS |
All versions, plus listed versions 1.0.0-11.0.3-1 |
None known |
python-oauthlibUbuntu:18.04:LTS |
All versions, plus listed versions 2.0.1-12.0.4-12.0.6-1 |
None known |
python-oauthlibUbuntu:20.04:LTS |
All versions, plus listed versions 2.1.0-13.1.0-1ubuntu13.1.0-1ubuntu2 |
None known |
Show 4 moreShow less
| Package | Affected | Fixed |
|---|---|---|
python-oauthlibUbuntu:22.04:LTS |
All versions, plus listed versions 3.1.0-23.1.1-13.2.0-13.2.0-1ubuntu0.1 |
None known |
python-oauthlibUbuntu:24.04:LTS |
All versions, plus listed versions 3.2.2-1 |
None known |
python-oauthlibUbuntu:26.10 |
All versions, plus listed versions 3.3.1-1build13.3.1-2 |
None known |
python-oauthlibUbuntu:26.04:LTS |
All versions, plus listed versions 3.2.2-33.3.1-13.3.1-1build1 |
None known |
History
| Recorded | Changed | Sources |
|---|---|---|
| affected | OSV | |
| facts | EUVD, NVD | |
| references | CVE List | |
| 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-118669 is a high vulnerability (CVSS 8.4) in Oauthlib, published October 28, 2026. No source lists public exploit code. EPSS puts the chance of exploitation in the next 30 days at 0.31%, the 24th percentile. Fixed in oauthlib 4.0.0.
References
github.com/oauthlib/oauthlib/security/advisories/GHSA-7984-qgvg-3j9c
github.com/oauthlib/oauthlib/pull/920
github.com/oauthlib/oauthlib/commit/c951a1d09f99f14e3240973fa83c4f4287d4753d
github.com/oauthlib/oauthlib/releases/tag/v4.0.0
nvd.nist.gov/vuln/detail/CVE-2026-118669
github.com/advisories/GHSA-7984-qgvg-3j9c
Left out here: 2 versions and the rest of 2 source descriptions. The JSON record has them.