Threats affecting pkg:pypi/oauthlib
4 threats
Most recently published first
| Severity | CVSS | Signals | Threat | Source | Published | Score and star |
|---|---|---|---|---|---|---|
| High | 8.4 | CVE-2026-118669oauthlib · Incorrect Authorization High8.4CVE Database V5CVE-2026-118669 OAuthLib versions prior to 4.0.0 contain an incorrect authorization vulnerability in the client_credentials and Resource Owner Password Credentials token grant handlers. This flaw allows a lower-privilege authenticated client to impersonate another client by supplying a different client_id, potentially resulting in issuance of tokens with unauthorized grants or scopes. The issue is resolved in version 4.0.0. | CVE Database V5 | |||
| High | 8.5 | CVE-2026-49272OAuthLib · Bearer token can be retrieved as long as client knows a valid client ID for device workflow High8.5GCVE DatabaseCVE-2026-49272 OAuthLib versions from 3.3.0 up to but not including 4.0.0 contain a vulnerability in the device code grant workflow (RFC 8628). The token endpoint does not properly validate the device_code parameter, allowing an attacker who knows a valid client ID for a public client configured for device workflow to obtain a bearer token without a valid device_code. This flaw arises because the DeviceCodeGrant.validate_token_request method lacks proper device_code validation. The issue is fixed in version 4.0.0. | GCVE Database | |||
| Medium | 6.8 | EPSS 0.2% | Medium6.8EPSS 0.2%GCVE DatabaseCVE-2026-49265 ## Summary A timing side-channel vulnerability exists in the PKCE (RFC 7636) implementation of the Authorization Code Grant flow. The `code_challenge_method_plain` function uses Python's standard `==` operator for string comparison instead of a constant-time comparison function, potentially allowing timing-based attacks. ## Affected Component - File: `oauthlib/oauth2/rfc6749/grant_types/authorization_code.py` - Functions: `code_challenge_method_plain`, `code_challenge_method_s256` - Vulnerability Type: CWE-208 (Observable Timing Discrepancy) ## Technical Details Python's `==` operator uses short-circuit evaluation when comparing strings: 1. Returns `False` immediately if lengths differ 2. Compares characters left-to-right, stopping at first mismatch This means comparison time varies linearly with the length of the common prefix between the attacker-supplied verifier and the stored challenge, creating a measurable timing oracle. ## Proof of Concept Tested locally against oauthlib source (network jitter eliminated to isolate pure Python execution time): | Input | Result | Time (10M iterations) | |---|---|---| | Wrong first char (`B` + `A`*49) | Fast reject | 0.34106s | | 49 chars correct (`A`*49 + `B`) | Deep compare | 0.37847s | | **Difference** | | **0.03741s** | The ~37ms delta over 10M iterations corresponds to nanosecond-level differences per call, which are statistically exploitable under controlled conditions. ## Attack Scenario 1. Attacker intercepts `authorization_code` via Custom URI Scheme Hijacking 2. PKCE blocks token request — attacker lacks `code_verifier` 3. Attacker sends repeated requests to `/token` endpoint measuring response times 4. Using timing oracle, attacker recovers `code_verifier` character by character 5. Attacker obtains Access Token → Account Takeover > **Note:** Practical exploitability is limited due to the single-use nature of > authorization codes and real-world network noise. However, the vulnerable > pattern should be corrected as a defense-in-depth measure. ## Recommended Fix Replace `==` with `hmac.compare_digest()` for constant-time comparison: cr: Elvin Latifli | GCVE Database | ||
| Medium | 6.1 | EPSS 0.2% | CVE-2026-49264Oauthlib : Unsafe JSONP callback injection Medium6.1EPSS 0.2%GCVE DatabaseCVE-2026-49264 ### Summary When `enable_jsonp=True`, oauthlib's `RevocationEndpoint` reflects the user-supplied `callback` parameter directly into JavaScript response bodies on both success and error paths without validating that it is a legal JSONP callback name. This allows arbitrary JavaScript response generation instead of a restricted function call, making the documented JSONP revocation feature unsafe for browser-based JSONP consumption when attackers can influence `callback`. ### Details The issue is in `oauthlib/oauth2/rfc6749/endpoints/revocation.py`. When `enable_jsonp=True` is passed to the `RevocationEndpoint` constructor, two code paths wrap the response body using the user-supplied `request.callback` parameter: ```python # Error response path (line 72-73): if self.enable_jsonp and request.callback: response_body = '{}({});'.format(request.callback, response_body) # Success response path (line 81-82): if self.enable_jsonp and request.callback: response_body = request.callback + '();' ``` The `request.callback` value comes from HTTP request parameters, either the query string or POST body, via the `Request` class in `oauthlib/common.py` (lines 394-395), which merges query and body parameters into `_params`. Any value the client sends as `callback` is used verbatim. There is no validation of any kind on the callback parameter: - No check that it is a valid JavaScript identifier - No whitelist of allowed characters - No escaping or sanitization A safe JSONP implementation must validate that the callback is a legal JavaScript function name (e.g., matching `^[a-zA-Z_$][a-zA-Z0-9_$.]*$`). Without this, the attacker controls the JavaScript code returned in the response body. This is the standard mitigation used by jQuery, Express.js, Google APIs, and other major JSONP implementations. **How the injection works:** An attacker sends a revocation request with a crafted callback value: ``` POST /revoke HTTP/1.1 Content-Type: application/x-www-form-urlencoded token=anything&callback=alert(document.cookie)// ``` The server responds with: ``` alert(document.cookie)//({"error": "invalid_client"}); ``` This is syntactically valid JavaScript. `alert(document.cookie)` executes as a statement, and `//` comments out the rest of the line. The attacker has full control over the code that appears before the `//`. **Execution context and attack surface:** JSONP works by having a browser load a remote script via `<script src="...">`. The loaded script executes in the origin of the **including page**, not the remote server. This means a `<script src="https://auth.example.com/revoke?token=x&callback=payload">` tag on `evil.com` would execute the payload in `evil.com`'s context, not the auth server's context. The impact comes from client-side integrations that consume this endpoint as trusted JSONP. If a legitimate OAuth client includes `<script src>` pointed at the revocation endpoint and an attacker can influence the callback value (e.g., via query parameter injection, a reflected value, or a man-in-the-middle downgrade), the attacker controls what code runs in the client application's origin. The authorization server becomes a source of attacker-controlled JavaScript that client applications trust and execute. Note: the `enable_jsonp` parameter defaults to `False`, so only deployments that explicitly opt in are affected. However, this is a supported, documented library feature, not a debug flag. The client-side library includes `prepare_token_revocation_request()` with an explicit `callback` parameter (`oauthlib/oauth2/rfc6749/parameters.py`, line 174), and the documentation shows JSONP revocation as a use case (`oauthlib/oauth2/rfc6749/clients/base.py`, lines 351-358). The existing test suite tests JSONP callback reflection with a benign value (`test_revocation_endpoint.py`, lines 91-101) but does not test for injection. Deployments that enable JSONP typically do so to support older browsers or cross-origin revocation from JavaScript clients, these are exactly the environments most sensitive to script injection. ### PoC **Requirements:** Python 3.x with oauthlib installed (`pip install oauthlib`). ```python from oauthlib.oauth2.rfc6749.endpoints.revocation import RevocationEndpoint from oauthlib.oauth2.rfc6749.request_validator import RequestValidator class FailValidator(RequestValidator): """Auth fails -> triggers error response path (lines 72-73).""" def client_authentication_required(self, request, *a, **kw): return True def authenticate_client(self, request, *a, **kw): return False def authenticate_client_id(self, client_id, request, *a, **kw): return False class PassValidator(RequestValidator): """Auth passes -> triggers success response path (lines 81-82).""" def client_authentication_required(self, request, *a, **kw): return False def authenticate_client_id(self, client_id, request, *a, **kw): return True def revoke_token(self, token, token_type_hint, request, | GCVE Database |
Page 1 of 1