From c77d816548bd768df262ba0204904168584c0bd1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Padilla?= Date: Thu, 12 Mar 2026 12:46:08 -0400 Subject: [PATCH] Merge commit from fork MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: José Padilla CVE: CVE-2026-32597 Upstream-Status: Backport [https://github.com/jpadilla/pyjwt/commit/051ea341b5573fe3edcd53042f347929b92c2b92] Dropped changes to the changelog, version bump and tests during backport. Signed-off-by: Ankur Tyagi --- jwt/api_jws.py | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/jwt/api_jws.py b/jwt/api_jws.py index 654ee0b..db2c80f 100644 --- a/jwt/api_jws.py +++ b/jwt/api_jws.py @@ -137,7 +137,7 @@ class PyJWS: header: dict[str, Any] = {"typ": self.header_typ, "alg": algorithm_} if headers: - self._validate_headers(headers) + self._validate_headers(headers, encoding=True) header.update(headers) if not header["typ"]: @@ -208,6 +208,8 @@ class PyJWS: payload, signing_input, header, signature = self._load(jwt) + self._validate_headers(header) + if header.get("b64", True) is False: if detached_payload is None: raise DecodeError( @@ -327,14 +329,35 @@ class PyJWS: if not alg_obj.verify(signing_input, prepared_key, signature): raise InvalidSignatureError("Signature verification failed") - def _validate_headers(self, headers: dict[str, Any]) -> None: + # Extensions that PyJWT actually understands and supports + _supported_crit: set[str] = {"b64"} + + def _validate_headers( + self, headers: dict[str, Any], *, encoding: bool = False + ) -> None: if "kid" in headers: self._validate_kid(headers["kid"]) + if not encoding and "crit" in headers: + self._validate_crit(headers) def _validate_kid(self, kid: Any) -> None: if not isinstance(kid, str): raise InvalidTokenError("Key ID header parameter must be a string") + def _validate_crit(self, headers: dict[str, Any]) -> None: + crit = headers["crit"] + if not isinstance(crit, list) or len(crit) == 0: + raise InvalidTokenError("Invalid 'crit' header: must be a non-empty list") + for ext in crit: + if not isinstance(ext, str): + raise InvalidTokenError("Invalid 'crit' header: values must be strings") + if ext not in self._supported_crit: + raise InvalidTokenError(f"Unsupported critical extension: {ext}") + if ext not in headers: + raise InvalidTokenError( + f"Critical extension '{ext}' is missing from headers" + ) + _jws_global_obj = PyJWS() encode = _jws_global_obj.encode