Threats tagged 'brew-mcpm-cve-2026-114617'
1 threat
Most recently published first
| Severity | CVSS | Signals | Threat | Source | Published | Score and star |
|---|---|---|---|---|---|---|
| Medium | 4.2 | EPSS 0.2% | CVE-2026-114617Authlib · ID token can disable its own nonce validation via the nonce_supported claim Medium4.2EPSS 0.2%GCVE DatabaseCVE-2026-114617 ### Summary `OpenIDMixin.parse_id_token()` reads the `nonce_supported` claim from the ID token it is validating. When that claim is boolean `false`, the expected nonce is set to `None` and nonce validation is skipped for that token. An ID token that carries this claim is therefore accepted in a session whose nonce does not match. A captured, validly signed ID token belonging to a victim can be replayed into an attacker-controlled session, authenticating the attacker as the victim at the relying party. The code is identical in `authlib/integrations/base_client/sync_openid.py:82-83` and `authlib/integrations/base_client/async_openid.py:84-85`, so all framework integrations are affected. Fixed versions: none; reproduced on 1.8.0 (commit c529a61a). Preconditions: the ID token must carry a valid signature and pass `iss` and `aud` validation, and the attacker must be able to supply it to `parse_id_token()`. Authorization code flow is not affected. Implicit and hybrid relying parties, and applications calling `parse_id_token()` directly, are affected. ### Details ## Affected code `authlib/integrations/base_client/sync_openid.py:80-85`, in `parse_id_token()`: ```python claims = claims_cls(token.claims, token.header, claims_options, claims_params) # https://github.com/authlib/authlib/issues/259 if claims.get("nonce_supported") is False: claims.params["nonce"] = None claims.validate(leeway=leeway) ``` `authlib/integrations/base_client/async_openid.py:82-86` contains the same code. ## Source of the claim `claims` is constructed from `token.claims`, which is the decoded payload of the ID token passed to `parse_id_token()`: ```python token = jwt.decode( token["id_token"], key=key_set, registry=JWSRegistry(algorithms=alg_values, strict_check_header=False), ) ... claims = claims_cls(token.claims, token.header, claims_options, claims_params) ``` `claims.get("nonce_supported")` therefore resolves against the ID token payload. It is not read from `load_server_metadata()`, from client configuration, or from any other source under the relying party's control. ## Effect on validation `IDToken.validate_nonce()` at `authlib/oidc/core/claims.py:69-83` performs the comparison only when the expected value is truthy: ```python nonce_value = self.params.get("nonce") if nonce_value: if "nonce" not in self: raise MissingClaimError("nonce") if nonce_value != self["nonce"]: raise InvalidClaimError("nonce") ``` Assigning `claims.params["nonce"] = None` makes `nonce_value` falsy, so both the presence check and the equality check are skipped. No error is raised and `claims.validate()` completes normally. The docstring of that same method states the requirement: > If present in the ID Token, Clients MUST verify that the nonce Claim Value is equal to the value of the nonce parameter sent in the Authentication Request. ## Trigger condition The comparison is `is False`, so only a JSON boolean `false` activates the branch. A string value `"false"` does not, and nonce validation proceeds normally in that case. ## Origin The branch was added in commit `3ca7333c` ("Skip verifying nonce for Apple case") to accommodate a provider that emits a `nonce_supported` claim, as referenced by the inline comment pointing to issue #259. ## Remediation Read the flag from server metadata or client configuration rather than from the token: ```python metadata = self.load_server_metadata() if metadata.get("nonce_supported") is False: claims.params["nonce"] = None ``` This preserves the behavior for relying parties configured against a provider that does not support nonces, while preventing the token from determining whether it is subject to nonce validation. ### Proof of concept ## Environment - authlib 1.8.0, commit `c529a61a` (tag `v1.8.0`) - Python 3.14 - joserfc 1.7.5 - No network access required ``` git clone https://github.com/authlib/authlib.git && cd authlib git checkout c529a61a python3 -m venv .venv .venv/bin/pip install -e . joserfc==1.7.5 .venv/bin/python poc.py ``` ## Configuration The relying party is a subclass of the shipped `OpenIDMixin` supplying only `client_id` and `load_server_metadata()`. `fetch_jwk_set()` returns `metadata["jwks"]` directly when the key set is present in metadata, so no HTTP request is made and no part of the validation path is stubbed. The signing key is a generated RSA key. All three tokens are signed with it, carry `iss` and `aud` matching the relying party configuration, and are within their validity window. The relying party's session nonce is `nonce-the-rp-actually-generated`; every token carries the different nonce `nonce-from-the-captured-token`. ## poc.py ```python from joserfc import jwt from joserfc.jwk import RSAKey from authlib.integrations.base_client.sync_openid import OpenIDMixin ISSUER = "https://as.example" CLIENT_ID = "rp-client" KEY = RSAKey.generate_key(2048, parameters={"kid": "k1"}) JWKS = {"keys": [KEY.as_dict(private=Fal | GCVE Database |
Page 1 of 1