From patchwork Fri Oct 16 02:33:14 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: "Hetvi Thakar -X (hthakar - E INFOCHIPS PRIVATE LIMITED at Cisco)" X-Patchwork-Id: 100926 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id AC964CCA48B for ; Fri, 16 Oct 2026 02:33:31 +0000 (UTC) Received: from rcdn-iport-2.cisco.com (rcdn-iport-2.cisco.com [173.37.86.73]) by mx.groups.io with SMTP id smtpd.msgproc02-g2.13504.1792118004184969055 for ; Thu, 15 Oct 2026 19:33:24 -0700 Authentication-Results: mx.groups.io; dkim=fail reason="dkim: message contains an insecure body length tag" header.i=@cisco.com header.s=iport01 header.b=HJMciRDi; spf=pass (domain: cisco.com, ip: 173.37.86.73, mailfrom: hthakar@cisco.com) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=cisco.com; i=@cisco.com; l=6449; q=dns/txt; s=iport01; t=1792118004; x=1793327604; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=XCoAi8D7PsKTxQeVmE8o+s3x/OLyvZ0IqTTbOwydLCA=; b=HJMciRDiQmwd+vNrp5N6OjCGoqgxB6Kl+0+y9zhw42f2UnPpnyvkHevt GXpXQfhApRuwOMI+fWX+sgZZSkPgcbEp2adWhOPOlcCQrEmHaTv0e0sqg adogTOHO9dkc5qnPLjn9qTKWq23mNLpwxJ2tegAXbxnM8eeUkf34a66DO 8STFfwDnJUf9jY2nuIQvsDVN3wdYl7o+2lBNkN9rIdiOvHAmgevIGUPYH ydGJyXNPDGKuEqFI5helRMeW/40lgkIDXuXEZcUgvnPaesolzUNZyfgyK qyzpzxX5cEju5DYyoF9pWDdvWUlSaPhbOwIUEVZYnCjVg4fp+GGv9nvxH A==; X-CSE-ConnectionGUID: MiP1JT3FTFCtscxrq5m6wQ== X-CSE-MsgGUID: lC240llRRLWBGBMvT+/57A== X-IPAS-Result: A0BLAgDZi9Fq/5L/Ja1aglmCV3VgQ0kDhFSRcwOeHIF+DwEBAQ9EDQQBAYUFAo4VAiY0CQ4BAgQDAgMBAQEBAQEBAQEBAQEKAQEFAQEBAgEHBYEOE4ZPDZASAQIBAyMECwEYAS0QHAMBAgMCJgICKyMIEAmDAgGCdAMRvGd6fzOBAYMpAYFU2zIBCxQBBYEFLoVAgx8BhQNdGAGEfCcbG4FygRWDaYEFgVwCgSeEFIJqBIIigQyBWh6VKUiBAhwDWSwBVRMNCgsHBYFoAzUSKhVuMh2BIz4XL1gbBgWBHYEgghYjGTZ6gQlegSspYAEQF4EJggcCglSCAAIBSUEOB0VTCSVDEkcmIggSCQETGjALgRs4PAkoQRcMcwwdBXIIAg0JBykYDUgRLDcVGQQ9AW4HkhMegmUHKl0BKwR7gS0epVehDwoog3aMIpU6GjOqbwuYfY4Klk+EaYFoPIFZcBWDIglKGQ+OOYNrzlonMgIJAy8BAQcCBwEMAQMLgWiQAIF+AQE IronPort-Data: A9a23:RLGMtKrB2gbHw0oezLgylGdH33JeBmJJZBIvgKrLsJaIsI4StFCzt garIBmCOvjcMzD0L4t3a4vio0MBv8PXx9YwG1M/+yowECsWoOPIVI+TRqvS04x+DSFioGZPt Zh2hgzodZhsJpPkjk7zdOWn9T8jhfngqoPUUIbsIjp2SRJvVBAvgBdin/9RqoNziLBVOSvV0 T/Ji5OZYgDNNwJcaDpOtfvb8U035ZwehRtB1rAATaET1LPhvyF94KI3fcmZM3b+S49IKe+2L 86r5K255G7Q4yA2AdqjlLvhGmVSKlIFFVHT4pb+c/HKbilq/kTe4I5iXBYvQRs/ZwGyojxE4 I4lWapc5useFvakdOw1C3G0GszlVEFM0OevzXOX6aR/w6BaGpfh660GMa04AWEX0sN2OThsy ac2FB4mcguIl/ivnbflVdA506zPLOGzVG8ekmtrwTecCbMtRorOBv2bo9RZxzw3wMtJGJ4yZ eJANmEpN0uGOUASfA5LVvrSn8/w7pX7Wz1EqFuWrLAf6GnIxws327/oWDbQUoHQHJQIwB/I/ Qoq+Uz9KUtGbNib8wChzViDrMrRoWC8Bd07QejQGvlCxQf7KnYoIBoOWF22pPO0hkKzV5dTJ lIZ/gIqrLMu7wqsVtT7UhiyrXKIsxJaXMBfe9DW8ymXwabSpgLcDW8eQ3sZOZottdQ9Qnoh0 Vrhc87VOAGDeYa9ERq1nop4ZxvrUcTJBQfuvRM5cDY= IronPort-HdrOrdr: A9a23:RhqSIqkWsRyKsHmq45sGBK65ZPDpDfLy3DAbv31ZSRFFG/FwWf rAoB19726TtN9xYgBGpTnuAsi9qB/nmKKdpLNhX4tKPzOW3FdAUrsD0WKK+VSJcEfDH6xmpM JdmsNFZuEYY2IXsS/S2njALz9Z+qjlzImYwcHD0nxqUQZmL4tk7wt/F0KnN3cefng/OXL8f6 DsnPauYFGbCA8qUvg= X-Talos-CUID: 9a23:WZhhwW8/aNBq5+4JZTOVv2sVIpkHTibz8Fn7P1SzGXxwFbjLVmbFrQ== X-Talos-MUID: 9a23:0nIfRARGUOmeRor0RXTor2s+bMNs2Z6KN2oiu7AYh4rDaHNZbmI= X-IronPort-Anti-Spam-Filtered: true X-IronPort-AV: E=Sophos;i="6.27,161,1787011200"; d="scan'208";a="521956183" Received: from rcdn-l-core-09.cisco.com ([173.37.255.146]) by rcdn-iport-2.cisco.com with ESMTP/TLS/TLS_AES_256_GCM_SHA384; 16 Oct 2026 02:33:23 +0000 Received: from sjc-ads-5245.cisco.com (sjc-ads-5245.cisco.com [10.28.23.9]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by rcdn-l-core-09.cisco.com (Postfix) with ESMTPS id 1ADB818000497; Fri, 16 Oct 2026 02:33:23 +0000 (GMT) Received: by sjc-ads-5245.cisco.com (Postfix, from userid 1887505) id B70CACBF201; Thu, 15 Oct 2026 19:33:22 -0700 (PDT) From: "Hetvi Thakar -X (hthakar - E INFOCHIPS PRIVATE LIMITED at Cisco)" To: openembedded-devel@lists.openembedded.org Cc: xe-linux-external@cisco.com Subject: [meta-python][wrynose][PATCH 1/9] python3-pyjwt: fix CVE-2026-103001 Date: Thu, 15 Oct 2026 19:33:14 -0700 Message-Id: <20261016023322.344365-2-hthakar@cisco.com> X-Mailer: git-send-email 2.35.6 In-Reply-To: <20261016023322.344365-1-hthakar@cisco.com> References: <20261016023322.344365-1-hthakar@cisco.com> MIME-Version: 1.0 X-Auto-Response-Suppress: DR, OOF, AutoReply X-Outbound-Client-TLS: ANONYMOUS;sjc-ads-5245.cisco.com [10.28.23.9];TLSv1.3;TLS_AES_256_GCM_SHA384;256 X-Outbound-SMTP-Client: 10.28.23.9, sjc-ads-5245.cisco.com X-Outbound-Node: rcdn-l-core-09.cisco.com List-Id: X-Webhook-Received: from 45-33-107-173.ip.linodeusercontent.com [45.33.107.173] by aws-us-west-2-korg-lkml-1.web.codeaurora.org with HTTPS for ; Fri, 16 Oct 2026 02:33:31 -0000 X-Groupsio-URL: https://lists.openembedded.org/g/openembedded-devel/message/131014 From: Hetvi Thakar This patch applies the upstream fix as referenced in [2], using the commit shown in [1]. [1] https://github.com/jpadilla/pyjwt/commit/0c87c8c8b1a74cac99ad8115f3050efcb7fbed35 [2] https://github.com/jpadilla/pyjwt/security/advisories/GHSA-gvp8-978c-rx2q Signed-off-by: Hetvi Thakar --- .../python/files/CVE-2026-103001.patch | 128 ++++++++++++++++++ .../python/python3-pyjwt_2.12.1.bb | 2 +- 2 files changed, 129 insertions(+), 1 deletion(-) create mode 100644 meta-python/recipes-devtools/python/files/CVE-2026-103001.patch diff --git a/meta-python/recipes-devtools/python/files/CVE-2026-103001.patch b/meta-python/recipes-devtools/python/files/CVE-2026-103001.patch new file mode 100644 index 0000000000..66e4aafcb7 --- /dev/null +++ b/meta-python/recipes-devtools/python/files/CVE-2026-103001.patch @@ -0,0 +1,128 @@ +From 0c87c8c8b1a74cac99ad8115f3050efcb7fbed35 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jos=C3=A9=20Padilla?= +Date: Tue, 8 Sep 2026 15:10:07 -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-103001 +Upstream-Status: Backport [https://github.com/jpadilla/pyjwt/commit/0c87c8c8b1a74cac99ad8115f3050efcb7fbed35] + +(cherry picked from commit 0c87c8c8b1a74cac99ad8115f3050efcb7fbed35) +Signed-off-by: Hetvi Thakar +--- + jwt/api_jwt.py | 20 +++++++++------- + tests/test_api_jwt.py | 56 +++++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 67 insertions(+), 9 deletions(-) + +diff --git a/jwt/api_jwt.py b/jwt/api_jwt.py +index 429c2d7..f298ea9 100644 +--- a/jwt/api_jwt.py ++++ b/jwt/api_jwt.py +@@ -76,16 +76,18 @@ class PyJWT: + if options is None: + return self.options + ++ merged_options = cast("Options", dict(options)) ++ + # (defensive) set defaults for verify_x to False if verify_signature is False +- if not options.get("verify_signature", True): +- options["verify_exp"] = options.get("verify_exp", False) +- options["verify_nbf"] = options.get("verify_nbf", False) +- options["verify_iat"] = options.get("verify_iat", False) +- options["verify_aud"] = options.get("verify_aud", False) +- options["verify_iss"] = options.get("verify_iss", False) +- options["verify_sub"] = options.get("verify_sub", False) +- options["verify_jti"] = options.get("verify_jti", False) +- return {**self.options, **options} ++ if not merged_options.get("verify_signature", True): ++ merged_options["verify_exp"] = merged_options.get("verify_exp", False) ++ merged_options["verify_nbf"] = merged_options.get("verify_nbf", False) ++ merged_options["verify_iat"] = merged_options.get("verify_iat", False) ++ merged_options["verify_aud"] = merged_options.get("verify_aud", False) ++ merged_options["verify_iss"] = merged_options.get("verify_iss", False) ++ merged_options["verify_sub"] = merged_options.get("verify_sub", False) ++ merged_options["verify_jti"] = merged_options.get("verify_jti", False) ++ return {**self.options, **merged_options} + + def encode( + self, +diff --git a/tests/test_api_jwt.py b/tests/test_api_jwt.py +index 8b54204..dd28816 100644 +--- a/tests/test_api_jwt.py ++++ b/tests/test_api_jwt.py +@@ -1,6 +1,7 @@ + import json + import time + from calendar import timegm ++from collections.abc import MutableMapping + from datetime import datetime, timedelta, timezone + from decimal import Decimal + +@@ -38,6 +39,61 @@ def payload() -> dict[str, object]: + + + class TestJWT: ++ def test_decode_does_not_mutate_options_when_signature_verification_is_disabled( ++ self, jwt: PyJWT ++ ) -> None: ++ options: Options = {"verify_signature": False} ++ token = jwt.encode({"claim": "value"}, "a" * 32, algorithm="HS256") ++ original_options = options.copy() ++ ++ jwt.decode(token, options=options) ++ ++ assert options == original_options ++ ++ def test_reused_options_do_not_disable_claim_verification(self, jwt: PyJWT) -> None: ++ options: Options = {"verify_signature": False} ++ token = jwt.encode({"exp": utc_timestamp() - 1}, "a" * 32, algorithm="HS256") ++ ++ jwt.decode(token, options=options) ++ options["verify_signature"] = True ++ ++ with pytest.raises(ExpiredSignatureError): ++ jwt.decode(token, "a" * 32, algorithms=["HS256"], options=options) ++ ++ def test_decode_complete_preserves_mutable_mapping_input(self, jwt: PyJWT) -> None: ++ class MappingWithoutCopy(MutableMapping[str, object]): ++ def __init__(self, values: dict[str, object]) -> None: ++ self.values = values ++ ++ def __getitem__(self, key: str) -> object: ++ return self.values[key] ++ ++ def __setitem__(self, key: str, value: object) -> None: ++ self.values[key] = value ++ ++ def __delitem__(self, key: str) -> None: ++ del self.values[key] ++ ++ def __iter__(self): ++ return iter(self.values) ++ ++ def __len__(self) -> int: ++ return len(self.values) ++ ++ options = MappingWithoutCopy({"verify_signature": False}) ++ token = jwt.encode({"claim": "value"}, "a" * 32, algorithm="HS256") ++ ++ jwt.decode_complete(token, options=options) # type: ignore[arg-type] ++ ++ assert dict(options) == {"verify_signature": False} ++ ++ def test_constructor_does_not_mutate_options_input(self, jwt: PyJWT) -> None: ++ options: Options = {"verify_signature": False} ++ ++ PyJWT(options=options) ++ ++ assert options == {"verify_signature": False} ++ + def test_jwt_with_options(self) -> None: + jwt = PyJWT(options={"verify_signature": False}) + assert jwt.options["verify_signature"] is False +-- +2.35.6 diff --git a/meta-python/recipes-devtools/python/python3-pyjwt_2.12.1.bb b/meta-python/recipes-devtools/python/python3-pyjwt_2.12.1.bb index bae7418565..56c48c79fe 100644 --- a/meta-python/recipes-devtools/python/python3-pyjwt_2.12.1.bb +++ b/meta-python/recipes-devtools/python/python3-pyjwt_2.12.1.bb @@ -10,6 +10,7 @@ SRC_URI += "file://CVE-2026-48522.patch \ file://CVE-2026-48524.patch \ file://CVE-2026-48525.patch \ file://CVE-2026-48526.patch \ + file://CVE-2026-103001.patch \ " SRC_URI[sha256sum] = "c74a7a2adf861c04d002db713dd85f84beb242228e671280bf709d765b03672b" @@ -25,4 +26,3 @@ RDEPENDS:${PN} = "\ " BBCLASSEXTEND = "native nativesdk" - From patchwork Fri Oct 16 02:33:15 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Hetvi Thakar -X (hthakar - E INFOCHIPS PRIVATE LIMITED at Cisco)" X-Patchwork-Id: 100921 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id 8FD23CCA48F for ; Fri, 16 Oct 2026 02:33:31 +0000 (UTC) Received: from rcdn-iport-8.cisco.com (rcdn-iport-8.cisco.com [173.37.86.79]) by mx.groups.io with SMTP id smtpd.msgproc01-g2.13366.1792118004224974679 for ; Thu, 15 Oct 2026 19:33:24 -0700 Authentication-Results: mx.groups.io; dkim=fail reason="dkim: message contains an insecure body length tag" header.i=@cisco.com header.s=iport01 header.b=K4ddWeu/; spf=pass (domain: cisco.com, ip: 173.37.86.79, mailfrom: hthakar@cisco.com) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=cisco.com; i=@cisco.com; l=3665; q=dns/txt; s=iport01; t=1792118004; x=1793327604; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=+s9tdyvKs7UprH0XVvUMU81iMl4ca8DQP2XL5r4MK+A=; b=K4ddWeu/6oj4lrHj/FChjEFNBwc8fHZvhz66wIyRLEd7jQ5net0sBROB Ck8jj7bC7xwETgqoMcsmJUKNuljS1JrE2WIUg1xfHq8d+sKwKj+jmu6kx bZDq8Ju4oNGPft5tfrq4ECSAL1fsYgBBZqOJeTId1Mh2/+SAdMwMk46t4 LQ1VBnw0mZZKvAYuEOp5Z8q5TdSZvnWd1Ow8ikHqM/0M0wAr4rbHS9JxP kZppNTKx4ceJjRFiQpkjQXmyikORNWSG1/CSrtAzkEbKt2NA18rfCixTL ppuenIcsTgFVBmryYMYdxLHtXYwLK2nBSTWsGjDDhaLC9WhltvvyMnKG8 g==; X-CSE-ConnectionGUID: jfkLBsMHQkOpZ/Z2VX0MmA== X-CSE-MsgGUID: O0qg99UoR8S+iSQQ5/6GWQ== X-IPAS-Result: A0BIAgDZi9Fq/5H/Ja1aglmCV3VgQ0kDlkcDnhyBfg8BAQEPRA0EAQGFBQKOFQImNAkOAQIEAwIDAQEBAQEBAQEBAQEBCgEBBQEBAQIBBwWBDhOGTw2QEgECAQMnCwEYAS0QHAMBAi8rIwgZgwIBgnQDEbxngXkzgQGDKQGBVNsyAQsUAQWBM4VAiCNdGAFEhDgnGxuBcoEVg2mBBYFcAoEnhn4EgiKBDIFalUdIgR4DWSwBVRMNCgsHBYFoAzUSKhVuMh2BIz4XgQcbBgWBHYEgghYjGTZ6gQlegSspYAEQF4EJggcCglSCAAIBSUEOB0VTCSVDEkcmIggSCQETGjALgRs4PAkoQRcMcwwdBXIIAg0JBykYDUgRLDcVGQQ+bgeSEx6CZXsTASt/EoEbHqVXoQ8KKIN2jCKVOhozhASUF5JUC5h9jgqWT4RpgWg8gVlwFYMiCUoZD445g2vOWicyAgkDLwEBBwIHDgMLgWiQAIEeYAEB IronPort-Data: A9a23:biZZp6B6Nl9VdhVW/3jiw5YqxClBgxIJ4kV8jS/XYbTApG4l1DRTz DccWj2CPaqPYTOjeNslOYi3/E4C75XQndY2OVdlrnsFo1CmBibm6XV1Cm+qYkt+++WaFBoPA /02M4eGcYZsCCCM/n9BC5C5xVFkz6aEW7HgP+DNPyF1VGdMRTwo4f5Zs7ZRbrVA357jXGthh fuo+5eBYQf8hWYtWo4pw/vrRC1H7ayaVAww5jTSVdgT1HfCmn8cCo4oJK3ZBxPQXolOE+emc P3Ixbe/83mx109F5gSNy+uTnuUiG9Y+DCDW4pZkc/HKbitq+kTe5p0G2M80Mi+7vdkmc+dZk 72hvbToIesg0zaldO41C3G0GAkmVUFKFSOuzXWX6aSuI0P6n3TEwfttKGstGK0h+cFvMyZ8r 8IocBUIR0XW7w626OrTpuhEnM8vKozveYgYoHwllWGfBvc9SpeFSKLPjTNa9G5v3YYVQrCEO pdfMGYyBPjDS0Un1lM/CI4+leShnFH0ciZTrxSeoq9fD237kVYhiOCyaYaNEjCMbeINh0nJ9 1/BxTTCQRAhDeXCjmSqzUv504cjmgu+Aur+DoaQ8eZnhlCWzGEfBBAaEFe2v/S9okq/QM5Eb UsM9ywjqKI/+ECmQp/6RRLQnZKflgQXV9wVF6gx7xuAj/KEpQ2YHWMDCDVGbbTKqfMLeNDj7 XfR9/uBONClmOT9pa61nltMkQ6PBA== IronPort-HdrOrdr: A9a23:dNcEaq538/dZrW9w8APXwBDXdLJyesId70hD6qm+c3Nom6uj5q eTdZsgtCMc5Ax9ZJhko6HjBEDiewK5yXcK2+ks1N6ZNWGM0ldAbrsSiLcKqAePJ8SRzIJgPI 5bAs5D4aXLfDtHpPe/xhWkGNA9x9TC2qWpieDCi0pJd2hRGthdB8MTMHfhLqWwLzM2faYEKA == X-Talos-CUID: 9a23:YX7XsWA52hCGuuD6Eytp92o+AeUFS3761EWXERWGOT5MTZTAHA== X-Talos-MUID: 9a23:bmmbHAoOK44VAWm3dhUezxY6Lcg5spmpMhA20pQ9gvDZcnJfBA7I2Q== X-IronPort-Anti-Spam-Filtered: true X-IronPort-AV: E=Sophos;i="6.27,161,1787011200"; d="scan'208";a="528007140" Received: from rcdn-l-core-08.cisco.com ([173.37.255.145]) by rcdn-iport-8.cisco.com with ESMTP/TLS/TLS_AES_256_GCM_SHA384; 16 Oct 2026 02:33:23 +0000 Received: from sjc-ads-5245.cisco.com (sjc-ads-5245.cisco.com [10.28.23.9]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by rcdn-l-core-08.cisco.com (Postfix) with ESMTPS id 1E09018000469; Fri, 16 Oct 2026 02:33:23 +0000 (GMT) Received: by sjc-ads-5245.cisco.com (Postfix, from userid 1887505) id BD680CBF202; Thu, 15 Oct 2026 19:33:22 -0700 (PDT) From: "Hetvi Thakar -X (hthakar - E INFOCHIPS PRIVATE LIMITED at Cisco)" To: openembedded-devel@lists.openembedded.org Cc: xe-linux-external@cisco.com Subject: [meta-python][wrynose][PATCH 2/9] python3-pyjwt: fix CVE-2026-102274 Date: Thu, 15 Oct 2026 19:33:15 -0700 Message-Id: <20261016023322.344365-3-hthakar@cisco.com> X-Mailer: git-send-email 2.35.6 In-Reply-To: <20261016023322.344365-1-hthakar@cisco.com> References: <20261016023322.344365-1-hthakar@cisco.com> MIME-Version: 1.0 X-Auto-Response-Suppress: DR, OOF, AutoReply X-Outbound-Client-TLS: ANONYMOUS;sjc-ads-5245.cisco.com [10.28.23.9];TLSv1.3;TLS_AES_256_GCM_SHA384;256 X-Outbound-SMTP-Client: 10.28.23.9, sjc-ads-5245.cisco.com X-Outbound-Node: rcdn-l-core-08.cisco.com List-Id: X-Webhook-Received: from 45-33-107-173.ip.linodeusercontent.com [45.33.107.173] by aws-us-west-2-korg-lkml-1.web.codeaurora.org with HTTPS for ; Fri, 16 Oct 2026 02:33:31 -0000 X-Groupsio-URL: https://lists.openembedded.org/g/openembedded-devel/message/131013 From: Hetvi Thakar This patch applies the upstream fix as referenced in [2], using the commit shown in [1]. [1] https://github.com/jpadilla/pyjwt/commit/8915570a0bfda9f0ff0e34e7fb09bdb9d71580cf [2] https://github.com/jpadilla/pyjwt/security/advisories/GHSA-w6j9-cwv2-h6wq Signed-off-by: Hetvi Thakar --- .../python/files/CVE-2026-102274.patch | 63 +++++++++++++++++++ .../python/python3-pyjwt_2.12.1.bb | 1 + 2 files changed, 64 insertions(+) create mode 100644 meta-python/recipes-devtools/python/files/CVE-2026-102274.patch diff --git a/meta-python/recipes-devtools/python/files/CVE-2026-102274.patch b/meta-python/recipes-devtools/python/files/CVE-2026-102274.patch new file mode 100644 index 0000000000..6a49dac3be --- /dev/null +++ b/meta-python/recipes-devtools/python/files/CVE-2026-102274.patch @@ -0,0 +1,63 @@ +From 8915570a0bfda9f0ff0e34e7fb09bdb9d71580cf Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jos=C3=A9=20Padilla?= +Date: Tue, 8 Sep 2026 16:13:35 -0400 +Subject: [PATCH] Skip malformed JWKs in JWK sets + +CVE: CVE-2026-102274 +Upstream-Status: Backport [https://github.com/jpadilla/pyjwt/commit/8915570a0bfda9f0ff0e34e7fb09bdb9d71580cf] + +(cherry picked from commit 8915570a0bfda9f0ff0e34e7fb09bdb9d71580cf) +Signed-off-by: Hetvi Thakar +--- + jwt/api_jwk.py | 7 ++++++- + tests/test_api_jwk.py | 17 +++++++++++++++++ + 2 files changed, 23 insertions(+), 1 deletion(-) + +diff --git a/jwt/api_jwk.py b/jwt/api_jwk.py +index 4ae7cc3..5ee26b4 100644 +--- a/jwt/api_jwk.py ++++ b/jwt/api_jwk.py +@@ -79,7 +79,12 @@ class PyJWK: + f"Unable to find an algorithm for key: {self._jwk_data}", + ) from None + +- self.key = self.Algorithm.from_jwk(self._jwk_data) ++ try: ++ self.key = self.Algorithm.from_jwk(self._jwk_data) ++ except ValueError as error: ++ raise InvalidKeyError( ++ f"Unable to construct key from JWK: {error}" ++ ) from error + + @staticmethod + def from_dict(obj: JWKDict, algorithm: str | None = None) -> PyJWK: +diff --git a/tests/test_api_jwk.py b/tests/test_api_jwk.py +index 221e2e2..b081034 100644 +--- a/tests/test_api_jwk.py ++++ b/tests/test_api_jwk.py +@@ -224,6 +224,23 @@ class TestPyJWK: + + + class TestPyJWKSet: ++ @crypto_required ++ def test_should_skip_malformed_rsa_key_and_load_remaining_keys(self) -> None: ++ with open(key_path("jwk_rsa_key.json")) as keyfile: ++ malformed_key = json.loads(keyfile.read()) ++ ++ malformed_key["d"] = "AAAAAA" ++ for parameter in ("p", "q", "dp", "dq", "qi"): ++ del malformed_key[parameter] ++ ++ with open(key_path("jwk_rsa_pub.json")) as keyfile: ++ valid_key = json.loads(keyfile.read()) ++ ++ jwk_set = PyJWKSet.from_dict({"keys": [malformed_key, valid_key]}) ++ ++ assert len(jwk_set.keys) == 1 ++ assert jwk_set.keys[0].key_type == "RSA" ++ + @crypto_required + def test_should_load_keys_from_jwk_data_dict(self) -> None: + algo = RSAAlgorithm(RSAAlgorithm.SHA256) +-- +2.35.6 diff --git a/meta-python/recipes-devtools/python/python3-pyjwt_2.12.1.bb b/meta-python/recipes-devtools/python/python3-pyjwt_2.12.1.bb index 56c48c79fe..f7542cab2e 100644 --- a/meta-python/recipes-devtools/python/python3-pyjwt_2.12.1.bb +++ b/meta-python/recipes-devtools/python/python3-pyjwt_2.12.1.bb @@ -11,6 +11,7 @@ SRC_URI += "file://CVE-2026-48522.patch \ file://CVE-2026-48525.patch \ file://CVE-2026-48526.patch \ file://CVE-2026-103001.patch \ + file://CVE-2026-102274.patch \ " SRC_URI[sha256sum] = "c74a7a2adf861c04d002db713dd85f84beb242228e671280bf709d765b03672b" From patchwork Fri Oct 16 02:33:16 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Hetvi Thakar -X (hthakar - E INFOCHIPS PRIVATE LIMITED at Cisco)" X-Patchwork-Id: 100919 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id 2E711CC6B38 for ; Fri, 16 Oct 2026 02:33:31 +0000 (UTC) Received: from rcdn-iport-7.cisco.com (rcdn-iport-7.cisco.com [173.37.86.78]) by mx.groups.io with SMTP id smtpd.msgproc01-g2.13365.1792118004177269008 for ; Thu, 15 Oct 2026 19:33:24 -0700 Authentication-Results: mx.groups.io; dkim=fail reason="dkim: message contains an insecure body length tag" header.i=@cisco.com header.s=iport01 header.b=jW+vt7N9; spf=pass (domain: cisco.com, ip: 173.37.86.78, mailfrom: hthakar@cisco.com) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=cisco.com; i=@cisco.com; l=6266; q=dns/txt; s=iport01; t=1792118004; x=1793327604; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=49w3mBKgraj6SNqABf4/6IlI0lPk/yPM3oZWboItfPo=; b=jW+vt7N93fCQCW4vpf9iriGYAF9jRgTKaXzN+gLsv+PyS0svxYVycFv5 MFtFWa6+4euJFSOWN7LVvBvlx71bm6Ys8KtFDZP43oL8vZ7FGkT6WQ3Gs OirVN8JHalI8KvbF3ngnJmO1DlvsdwZrUMOLROn5s0rCvmB3cpv/T0NQZ KALesw/uDTxvWhWNU2BygJnanDWA1H3ri52fTH0W535xQYOhyVM0lZieh WYKg26PBO/fUOeFQ4eRj1wQzIYkJEQG2l4H2HP1ToOa1ILBNCYFA8jfZV Ocrg3GIZFMyVf/O/b7kwvWtfgMtO7NAm0CZnQAnzT9Zty+aByV5Pdd5kY Q==; X-CSE-ConnectionGUID: KZrsxZLTR7GKdYUD483KeQ== X-CSE-MsgGUID: Tz8tIqbsSN2IHwjKT7fq5g== X-IPAS-Result: A0CYAwBdi9Fq/5D/Ja1aHgEBCxIMhGd1YENJA5ZHA6AaDwEBAQ9EDQQBAYUFAo4VAiY4EwECBAMCAwEBAQEBAQEBAQEBAQoBAQUBAQECAQcFgQ4Thk8NkBIBAgEDJwsBGAEtEBwDAQIvKyMIGYMCAYJ0AxG8YoF5M4EBgykBgVTbMgELFAEFgTOFQIgjXRgBRIMZgR8nGxuBcoEVg2mBBYFcAoglBIIigQyBWh6VKUiBHgNZLAFVEw0KCwcFgWgDNRIqFW4yHYEjPheBBxsGBYEdgSCCFiMZNnqBCV6BKylgARAXgQmCBwKCVIIAAgFJQQ4HRVMJJUMSRyYiCBIJARMaMAuBGzg8CShBFwxzDB0FcggCDQkHKRgNSBEsNxUZBD5uB5ITHoI4LXsTASsXaIEtHpMhkBWCIaEPCiiDdowilToaM6pvC5h9jgqVX3CEaYF/JYFZcBWDIglKGQ+OKw4Lg2DOWicyAgkDLwEBBwIHDgMLgWiRfgEB IronPort-Data: A9a23:D8IXCK2lzbiRLFJTwvbD5YJwkn2cJEfYwER7XKvMYLTBsI5bp2QAm mAfDzyDa/aJNjHxeotxbYi19hsB6pbSx9IwTwU+3Hw8FHgiRegpqji6wuYcGwvIc6UvmWo+t 512huHodZ5yEzmE4Ej9atANlFEkvYmQXL3wFeXYDS54QA5gWU8JhAlq8wIDqtYAbeORXUXX5 rsen+WFYAX7gmYtbDpNg06+gEoHUMra6WtwUmMWPZinjHeG/1EJAZQWI72GLneQauF8Au6gS u/f+6qy92Xf8g1FIovNfmHTKxBirhb6ZGBiu1IOM0SQqkEqSh8ajs7XAMEhhXJ/0F1lqTzeJ OJl7vRcQS9xVkHFdX90vxNwS0mSNoUekFPLzOTWXcG7lyX7n3XQL/pGL3MsJp0q3tpNXk5t+ c0lBGxdNTOOvrfjqF67YrEEasULNsLnOsYb/3pn1zycValgSpHYSKKM7thdtNsyrpkRRrCFO IxDNGcpNUicC/FMEg9/5JYWnPuoj3r2aRVTqUmeouw85G27IAlZjeOwbYeMIozWLSlTtnqK9 n7n5m7iOTdAFfyAyxm5rXy12+CayEsXX6pXTtVU7MVCh0WewGEWAhAaWVa35PW0lEO6c9ZeM FAPvC02oK4/8UamQtXwU1u/unHsg/IHc8BbH+t/7ESGzbDZpl7GQGMFVTVGLtchsafaWAAX6 7NApPuxbRQHjVFfYSv1Gmu8xd9qBRUoEA== IronPort-HdrOrdr: A9a23:i5smT6gd9nb+2NAoezLVHk8umHBQXgIji2hC6mlwRA09TyVXra +TdZMgpHjJYVkqOU3I9ersBEDEewK/yXcX2/h0AV7dZmnbUQKTRekIh7cKgQeQfhEWndQy6U 4PScRD4fTLfD5HZL7BkWqFOudl5sWb+6a1guqb5XJsQQZ2L5xE1W5Ce3+m+okcfng8OXL/f6 DsnvZ6mw== X-Talos-CUID: 9a23:ZOPUq21d7ic65b8C42rXZ7xfOfI/aW3v6EvqfGCbBVdUZOHFEnydwfYx X-Talos-MUID: 9a23:yIvY3wnNXmd+Krb0XU36dnpeJpd0wr2kE3sry7QmpMunCXN+ImqS2WE= X-IronPort-Anti-Spam-Filtered: true X-IronPort-AV: E=Sophos;i="6.27,161,1787011200"; d="scan'208";a="535551084" Received: from rcdn-l-core-07.cisco.com ([173.37.255.144]) by rcdn-iport-7.cisco.com with ESMTP/TLS/TLS_AES_256_GCM_SHA384; 16 Oct 2026 02:33:23 +0000 Received: from sjc-ads-5245.cisco.com (sjc-ads-5245.cisco.com [10.28.23.9]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by rcdn-l-core-07.cisco.com (Postfix) with ESMTPS id 22A1218000206; Fri, 16 Oct 2026 02:33:23 +0000 (GMT) Received: by sjc-ads-5245.cisco.com (Postfix, from userid 1887505) id C0E44CBF203; Thu, 15 Oct 2026 19:33:22 -0700 (PDT) From: "Hetvi Thakar -X (hthakar - E INFOCHIPS PRIVATE LIMITED at Cisco)" To: openembedded-devel@lists.openembedded.org Cc: xe-linux-external@cisco.com Subject: [meta-python][wrynose][PATCH 3/9] python3-pyjwt: fix CVE-2026-102269 Date: Thu, 15 Oct 2026 19:33:16 -0700 Message-Id: <20261016023322.344365-4-hthakar@cisco.com> X-Mailer: git-send-email 2.35.6 In-Reply-To: <20261016023322.344365-1-hthakar@cisco.com> References: <20261016023322.344365-1-hthakar@cisco.com> MIME-Version: 1.0 X-Auto-Response-Suppress: DR, OOF, AutoReply X-Outbound-Client-TLS: ANONYMOUS;sjc-ads-5245.cisco.com [10.28.23.9];TLSv1.3;TLS_AES_256_GCM_SHA384;256 X-Outbound-SMTP-Client: 10.28.23.9, sjc-ads-5245.cisco.com X-Outbound-Node: rcdn-l-core-07.cisco.com List-Id: X-Webhook-Received: from 45-33-107-173.ip.linodeusercontent.com [45.33.107.173] by aws-us-west-2-korg-lkml-1.web.codeaurora.org with HTTPS for ; Fri, 16 Oct 2026 02:33:31 -0000 X-Groupsio-URL: https://lists.openembedded.org/g/openembedded-devel/message/131012 From: Hetvi Thakar This patch applies the upstream fix as referenced in [2], using the commit shown in [1]. [1] https://github.com/jpadilla/pyjwt/commit/e6f48401001609a8f99e71fcaf355fb895d508a8 [2] https://github.com/jpadilla/pyjwt/security/advisories/GHSA-hxm8-2xgr-2p9m Signed-off-by: Hetvi Thakar --- .../python/files/CVE-2026-102269.patch | 133 ++++++++++++++++++ .../python/python3-pyjwt_2.12.1.bb | 1 + 2 files changed, 134 insertions(+) create mode 100644 meta-python/recipes-devtools/python/files/CVE-2026-102269.patch diff --git a/meta-python/recipes-devtools/python/files/CVE-2026-102269.patch b/meta-python/recipes-devtools/python/files/CVE-2026-102269.patch new file mode 100644 index 0000000000..ebf2d280cf --- /dev/null +++ b/meta-python/recipes-devtools/python/files/CVE-2026-102269.patch @@ -0,0 +1,133 @@ +From e6f48401001609a8f99e71fcaf355fb895d508a8 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jos=C3=A9=20Padilla?= +Date: Wed, 9 Sep 2026 09:46:01 -0400 +Subject: [PATCH] Reject non-canonical compact JWS segments + +CVE: CVE-2026-102269 +Upstream-Status: Backport [https://github.com/jpadilla/pyjwt/commit/e6f48401001609a8f99e71fcaf355fb895d508a8] + +(cherry picked from commit e6f48401001609a8f99e71fcaf355fb895d508a8) +Signed-off-by: Hetvi Thakar +--- + jwt/api_jws.py | 35 +++++++++++++++++++++++------------ + tests/test_api_jws.py | 11 +++++++++++ + tests/test_compressed_jwt.py | 8 ++++---- + 3 files changed, 38 insertions(+), 16 deletions(-) + +diff --git a/jwt/api_jws.py b/jwt/api_jws.py +index 5a91bce..2ee2f22 100644 +--- a/jwt/api_jws.py ++++ b/jwt/api_jws.py +@@ -28,6 +28,9 @@ if TYPE_CHECKING: + from .types import SigOptions + + _ALGORITHM_UNSET = object() ++_BASE64URL_ALPHABET = ( ++ b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_" ++) + + + class PyJWS: +@@ -291,6 +294,23 @@ class PyJWS: + + return headers + ++ @staticmethod ++ def _decode_base64url_segment(segment: bytes, name: str) -> bytes: ++ if len(segment) % 4 == 1 or any( ++ character not in _BASE64URL_ALPHABET for character in segment ++ ): ++ raise DecodeError(f"Invalid {name} padding") ++ ++ try: ++ decoded = base64url_decode(segment) ++ except (TypeError, binascii.Error) as err: ++ raise DecodeError(f"Invalid {name} padding") from err ++ ++ if base64url_encode(decoded) != segment: ++ raise DecodeError(f"Invalid {name} padding") ++ ++ return decoded ++ + def _load(self, jwt: str | bytes) -> tuple[bytes, bytes, dict[str, Any], bytes]: + if isinstance(jwt, str): + jwt = jwt.encode("utf-8") +@@ -304,10 +324,7 @@ class PyJWS: + except ValueError as err: + raise DecodeError("Not enough segments") from err + +- try: +- header_data = base64url_decode(header_segment) +- except (TypeError, binascii.Error) as err: +- raise DecodeError("Invalid header padding") from err ++ header_data = self._decode_base64url_segment(header_segment, "header") + + try: + header: dict[str, Any] = json.loads(header_data) +@@ -331,15 +348,9 @@ class PyJWS: + ) + payload = b"" + else: +- try: +- payload = base64url_decode(payload_segment) +- except (TypeError, binascii.Error) as err: +- raise DecodeError("Invalid payload padding") from err ++ payload = self._decode_base64url_segment(payload_segment, "payload") + +- try: +- signature = base64url_decode(crypto_segment) +- except (TypeError, binascii.Error) as err: +- raise DecodeError("Invalid crypto padding") from err ++ signature = self._decode_base64url_segment(crypto_segment, "crypto") + + return (payload, signing_input, header, signature) + +diff --git a/tests/test_api_jws.py b/tests/test_api_jws.py +index 01de813..7e0a97b 100644 +--- a/tests/test_api_jws.py ++++ b/tests/test_api_jws.py +@@ -658,6 +658,17 @@ class TestJWS: + + assert "Invalid crypto padding" in str(exc.value) + ++ def test_decode_rejects_non_canonical_crypto_segment( ++ self, jws: PyJWS, payload: bytes ++ ) -> None: ++ secret = "a" * 32 ++ token = jws.encode(payload, secret, algorithm="HS256") ++ header, encoded_payload, signature = token.split(".") ++ mutated_token = ".".join((header, encoded_payload, f"{signature}!!!!")) ++ ++ with pytest.raises(DecodeError, match="Invalid crypto padding"): ++ jws.decode(mutated_token, secret, algorithms=["HS256"]) ++ + def test_decode_with_algo_none_should_fail( + self, jws: PyJWS, payload: bytes + ) -> None: +diff --git a/tests/test_compressed_jwt.py b/tests/test_compressed_jwt.py +index 1968cb4..51c61a8 100644 +--- a/tests/test_compressed_jwt.py ++++ b/tests/test_compressed_jwt.py +@@ -22,8 +22,8 @@ def test_decodes_complete_valid_jwt_with_compressed_payload() -> None: + # Buffer.from(pako.deflateRaw('{"hello": "world"}')).toString('base64') + example_jwt = ( + b"eyJhbGciOiAiSFMyNTYiLCAidHlwIjogIkpXVCJ9" +- b".q1bKSM3JyVeyUlAqzy/KSVGqBQA=" +- b".08wHYeuh1rJXmcBcMrz6NxmbxAnCQp2rGTKfRNIkxiw=" ++ b".q1bKSM3JyVeyUlAqzy_KSVGqBQA" ++ b".AAn1elCJC5MQCYFwTwa2tjjtyLgqLUVU-Y1vFBsU8jo" + ) + decoded = CompressedPyJWT().decode_complete( + example_jwt, example_secret, algorithms=["HS256"] +@@ -33,7 +33,7 @@ def test_decodes_complete_valid_jwt_with_compressed_payload() -> None: + "header": {"alg": "HS256", "typ": "JWT"}, + "payload": example_payload, + "signature": ( +- b"\xd3\xcc\x07a\xeb\xa1\xd6\xb2W\x99\xc0\\2\xbc\xfa7" +- b"\x19\x9b\xc4\t\xc2B\x9d\xab\x192\x9fD\xd2$\xc6," ++ b"\x00\t\xf5zP\x89\x0b\x93\x10\t\x81pO\x06\xb6\xb68" ++ b"\xed\xc8\xb8*-ET\xf9\x8do\x14\x1b\x14\xf2:" + ), + } +-- +2.35.6 diff --git a/meta-python/recipes-devtools/python/python3-pyjwt_2.12.1.bb b/meta-python/recipes-devtools/python/python3-pyjwt_2.12.1.bb index f7542cab2e..a159f2fbbb 100644 --- a/meta-python/recipes-devtools/python/python3-pyjwt_2.12.1.bb +++ b/meta-python/recipes-devtools/python/python3-pyjwt_2.12.1.bb @@ -12,6 +12,7 @@ SRC_URI += "file://CVE-2026-48522.patch \ file://CVE-2026-48526.patch \ file://CVE-2026-103001.patch \ file://CVE-2026-102274.patch \ + file://CVE-2026-102269.patch \ " SRC_URI[sha256sum] = "c74a7a2adf861c04d002db713dd85f84beb242228e671280bf709d765b03672b" From patchwork Fri Oct 16 02:33:17 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Hetvi Thakar -X (hthakar - E INFOCHIPS PRIVATE LIMITED at Cisco)" X-Patchwork-Id: 100925 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id 90DD2CCA473 for ; Fri, 16 Oct 2026 02:33:31 +0000 (UTC) Received: from rcdn-iport-9.cisco.com (rcdn-iport-9.cisco.com [173.37.86.80]) by mx.groups.io with SMTP id smtpd.msgproc02-g2.13505.1792118004225238696 for ; Thu, 15 Oct 2026 19:33:24 -0700 Authentication-Results: mx.groups.io; dkim=fail reason="dkim: message contains an insecure body length tag" header.i=@cisco.com header.s=iport01 header.b=U1MmOKrV; spf=pass (domain: cisco.com, ip: 173.37.86.80, mailfrom: hthakar@cisco.com) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=cisco.com; i=@cisco.com; l=9643; q=dns/txt; s=iport01; t=1792118004; x=1793327604; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=o0tES20EJuvVNJFOiw+IpqYYRjfyd3RhoKpDNqFBWpU=; b=U1MmOKrVCkOJ9OQMI7j7ig9bdq6OmU7hPhlGEt9SXrFABt+U0CVsXFAZ LWvkyPTJmDwOQ1z62hllbfNSVsYbuBRxJsDL5EWn/OczLVp2IpJdGSwxs p+ovErlvlApQl2Of9fbVWhVTKQoKjD9sNxFDneGXX7u8NZT4ycrDvjonh P4SLRwtowLDysDBwNSWnmwyeSew8diCEqCXwJHz1gbnKQZY00YY7cWAyu ApEmNcT7ZVqG1lmUYx966Yu2NnXADh4U0xrio9bLzssUag8hrc0daTvBZ jHZG8LI9nBZ/Bqbv9LIHBDKfGit1eXt3XK4siFprtAZTcD9jepDQG4wi/ w==; X-CSE-ConnectionGUID: XdPmMppFT4esoDWDBbHV+A== X-CSE-MsgGUID: RK9CxGFUQ7iDYeHeO6O7hA== X-IPAS-Result: A0DOAgBdi9Fq/5X/Ja1aEwEBCQEBCxIMggULgld1YENJA5ZHA4ETggqafxSBag8BAQEPRA0EAQGFBQKOFQImNQgOAQIEAwIDAQEBAQEBAQEBAQEBCgEBBQEBAQIBBwWBDhOGTw2QEgECAQMnCwEZLRAcAgEBAi8kByMIGYMCAYJxAwMRBrxcgXkzgQGDKoFU2zIBCxQBBYEzgXODTYgjXRgBhHwnGxuBcoEVgnN2gQWBXAKBKwESAQmGXQSCIoEMgVqBA5RESIEeA1ksAVUTDQoLBwWBaAM1EioVbjIdgSM+F4EHGwYFgR2BIIIWIxk2eoEJXoErKWABEBeBCYIHAoJUggACAUlBDgdFUwklQxJHJiIIEgkBExowC4EbODwJKEEXDHMMHQVyCAINCQcpGA1IESw3FRkEPm4HkhMegmMCexMBKgF/EjxfHhySdJJHgTWfWgoog3aMIpU6GjOEBJQXklQLmH2FVIg2gU2HNox8UIRpgWkBOmlwcBU7gmcJShkPjjmDa85aJzICCQMvAQEHAgcOAwuBaJF+AQE IronPort-Data: A9a23:mT7R66orIrcmrWM13LycdsXfSzReBmJJZBIvgKrLsJaIsI4StFCzt garIBmOMq2PMTf2c9klPNvi/RhSuZOBnIU2TlRqrH1mRC8RoOPIVI+TRqvS04x+DSFioGZPt Zh2hgzodZhsJpPkjk7zdOWn9T8jhfngqoPUUIbsIjp2SRJvVBAvgBdin/9RqoNziLBVOSvV0 T/Ji5OZYgDNNwJcaDpOtfvb8U035ZwehRtB1rAATaET1LPhvyF94KI3fcmZM3b+S49IKe+2L 86r5K255G7Q4yA2AdqjlLvhGmVSKlIFFVHT4pb+c/HKbilq/kTe4I5iXBYvQRs/ZwGyojxE4 I4lWapc5useFvakdOw1C3G0GszlVEFM0OevzXOX6aR/w6BaGpfh660GMa04AWEX0tZ7OWRr7 eQ2FGwAdRevuM6cypKFCcA506zPLOGzVG8ekmtrwTecCbMtRorOBvyQo9RZxzw3wMtJGJ4yZ eJANmEpN0uGOUASfA5LWfrSn8/w7pX7Wz1EqFuWrLAf6GnIxws327/oWDbQUoHRGJ8LzxnI/ Qoq+UzDIUAxJPOx9APa816di8/Cun3cB4I7QejQGvlCxQf7KnYoIBoOWF22pPO0hkKzV5dTJ lIZ/gIqrLMu7wqsVtT7UhiyrXKIsxJaXMBfe9DW8ymXwabSpgLcDW8eQ3sYMpottdQ9Qnoh0 Vrhc87VOAGDeYa9ERq1nop4ZxvrUcTJBQfuvRM5cDY= IronPort-HdrOrdr: A9a23:2yxrsakQucVIWB9nda4C+LLQwzTpDfL03DAbv31ZSRFFG/FwWf rAoB19726StN9/YhAdcLy7VZVoBEmsl6KdgrNhWYtKIjOHhILAFugLhuHfKn/bakjDH4Vmu5 uIHZITNDTYNykdsS+D2njaL/8QhP+a7auvmeDSi11pTQ1sduVcyj0RMHfjLqWzLzM2fqbQ0/ Gnl7J6mwY= X-Talos-CUID: 9a23:skLlC283hrvVAaP0wMOVv34YIsUAamXz8CvdOEiUNkpDQp2rCnbFrQ== X-Talos-MUID: 9a23:y6dhkQpiLar2KiThcV4ezwtBZex4zIqTMR8MvaQLm8SjawsvOx7I2Q== X-IronPort-Anti-Spam-Filtered: true X-IronPort-AV: E=Sophos;i="6.27,161,1787011200"; d="scan'208";a="535269783" Received: from rcdn-l-core-12.cisco.com ([173.37.255.149]) by rcdn-iport-9.cisco.com with ESMTP/TLS/TLS_AES_256_GCM_SHA384; 16 Oct 2026 02:33:23 +0000 Received: from sjc-ads-5245.cisco.com (sjc-ads-5245.cisco.com [10.28.23.9]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by rcdn-l-core-12.cisco.com (Postfix) with ESMTPS id 25091180001CB; Fri, 16 Oct 2026 02:33:23 +0000 (GMT) Received: by sjc-ads-5245.cisco.com (Postfix, from userid 1887505) id C4E92CBF204; Thu, 15 Oct 2026 19:33:22 -0700 (PDT) From: "Hetvi Thakar -X (hthakar - E INFOCHIPS PRIVATE LIMITED at Cisco)" To: openembedded-devel@lists.openembedded.org Cc: xe-linux-external@cisco.com Subject: [meta-python][wrynose][PATCH 4/9] python3-pyjwt: fix CVE-2026-102267 Date: Thu, 15 Oct 2026 19:33:17 -0700 Message-Id: <20261016023322.344365-5-hthakar@cisco.com> X-Mailer: git-send-email 2.35.6 In-Reply-To: <20261016023322.344365-1-hthakar@cisco.com> References: <20261016023322.344365-1-hthakar@cisco.com> MIME-Version: 1.0 X-Auto-Response-Suppress: DR, OOF, AutoReply X-Outbound-Client-TLS: ANONYMOUS;sjc-ads-5245.cisco.com [10.28.23.9];TLSv1.3;TLS_AES_256_GCM_SHA384;256 X-Outbound-SMTP-Client: 10.28.23.9, sjc-ads-5245.cisco.com X-Outbound-Node: rcdn-l-core-12.cisco.com List-Id: X-Webhook-Received: from 45-33-107-173.ip.linodeusercontent.com [45.33.107.173] by aws-us-west-2-korg-lkml-1.web.codeaurora.org with HTTPS for ; Fri, 16 Oct 2026 02:33:31 -0000 X-Groupsio-URL: https://lists.openembedded.org/g/openembedded-devel/message/131016 From: Hetvi Thakar This patch applies the upstream fix as referenced in [2], using the commit shown in [1]. [1] https://github.com/jpadilla/pyjwt/commit/0a795b8e1f6ef08f634aa7086fc41cc6d5ce3e56 [2] https://github.com/jpadilla/pyjwt/security/advisories/GHSA-9v7f-9g4p-ffgj Signed-off-by: Hetvi Thakar --- .../python/files/CVE-2026-102267.patch | 223 ++++++++++++++++++ .../python/python3-pyjwt_2.12.1.bb | 1 + 2 files changed, 224 insertions(+) create mode 100644 meta-python/recipes-devtools/python/files/CVE-2026-102267.patch diff --git a/meta-python/recipes-devtools/python/files/CVE-2026-102267.patch b/meta-python/recipes-devtools/python/files/CVE-2026-102267.patch new file mode 100644 index 0000000000..97dfd88364 --- /dev/null +++ b/meta-python/recipes-devtools/python/files/CVE-2026-102267.patch @@ -0,0 +1,223 @@ +From 0a795b8e1f6ef08f634aa7086fc41cc6d5ce3e56 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jos=C3=A9=20Padilla?= +Date: Wed, 9 Sep 2026 20:20:46 -0400 +Subject: [PATCH] Reject redirects in PyJWKClient fetches + +CVE: CVE-2026-102267 +Upstream-Status: Backport [https://github.com/jpadilla/pyjwt/commit/0a795b8e1f6ef08f634aa7086fc41cc6d5ce3e56] + +(cherry picked from commit 0a795b8e1f6ef08f634aa7086fc41cc6d5ce3e56) +Signed-off-by: Hetvi Thakar +--- + jwt/jwks_client.py | 21 +++++++-- + tests/test_jwks_client.py | 91 ++++++++++++++++++++++++++++++++++----- + 2 files changed, 99 insertions(+), 13 deletions(-) + +diff --git a/jwt/jwks_client.py b/jwt/jwks_client.py +index 41f333a..cfc9003 100644 +--- a/jwt/jwks_client.py ++++ b/jwt/jwks_client.py +@@ -14,6 +14,19 @@ from .exceptions import PyJWKClientConnectionError, PyJWKClientError + from .jwk_set_cache import JWKSetCache + + ++class _NoRedirectHandler(urllib.request.HTTPRedirectHandler): ++ def redirect_request( ++ self, ++ req: urllib.request.Request, ++ fp: Any, ++ code: int, ++ msg: str, ++ headers: Any, ++ newurl: str, ++ ) -> None: ++ return None ++ ++ + class PyJWKClient: + def __init__( + self, +@@ -115,9 +128,11 @@ class PyJWKClient: + """ + try: + r = urllib.request.Request(url=self.uri, headers=self.headers) +- with urllib.request.urlopen( +- r, timeout=self.timeout, context=self.ssl_context +- ) as response: ++ handlers: list[Any] = [_NoRedirectHandler()] ++ if self.ssl_context is not None: ++ handlers.append(urllib.request.HTTPSHandler(context=self.ssl_context)) ++ opener = urllib.request.build_opener(*handlers) ++ with opener.open(r, timeout=self.timeout) as response: + jwk_set = json.load(response) + except (URLError, TimeoutError) as e: + if isinstance(e, HTTPError): +diff --git a/tests/test_jwks_client.py b/tests/test_jwks_client.py +index da68664..49471ac 100644 +--- a/tests/test_jwks_client.py ++++ b/tests/test_jwks_client.py +@@ -2,8 +2,10 @@ import contextlib + import io + import json + import ssl ++import threading + import time + from collections.abc import Iterator ++from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer + from unittest import mock + from urllib.error import HTTPError, URLError + from email.message import Message +@@ -12,6 +14,7 @@ import pytest + + import jwt + from jwt import PyJWKClient ++from jwt.jwks_client import _NoRedirectHandler + from jwt.api_jwk import PyJWK + from jwt.exceptions import PyJWKClientConnectionError, PyJWKClientError + +@@ -50,7 +53,10 @@ RESPONSE_DATA_NO_MATCHING_KID = { + + @contextlib.contextmanager + def mocked_success_response(data: object) -> Iterator[mock.Mock]: +- with mock.patch("urllib.request.urlopen") as urlopen_mock: ++ with mock.patch("urllib.request.build_opener") as build_opener_mock: ++ opener = mock.Mock() ++ build_opener_mock.return_value = opener ++ urlopen_mock = opener.open + response = mock.Mock() + response.__enter__ = mock.Mock(return_value=response) + response.__exit__ = mock.Mock() +@@ -61,7 +67,10 @@ def mocked_success_response(data: object) -> Iterator[mock.Mock]: + + @contextlib.contextmanager + def mocked_failed_response() -> Iterator[mock.Mock]: +- with mock.patch("urllib.request.urlopen") as urlopen_mock: ++ with mock.patch("urllib.request.build_opener") as build_opener_mock: ++ opener = mock.Mock() ++ build_opener_mock.return_value = opener ++ urlopen_mock = opener.open + urlopen_mock.side_effect = URLError("Fail to process the request.") + yield urlopen_mock + +@@ -70,7 +79,10 @@ def mocked_failed_response() -> Iterator[mock.Mock]: + def mocked_first_call_wrong_kid_second_call_correct_kid( + response_data_one: object, response_data_two: object + ) -> Iterator[mock.Mock]: +- with mock.patch("urllib.request.urlopen") as urlopen_mock: ++ with mock.patch("urllib.request.build_opener") as build_opener_mock: ++ opener = mock.Mock() ++ build_opener_mock.return_value = opener ++ urlopen_mock = opener.open + response = mock.Mock() + response.__enter__ = mock.Mock(return_value=response) + response.__exit__ = mock.Mock() +@@ -84,14 +96,20 @@ def mocked_first_call_wrong_kid_second_call_correct_kid( + + @contextlib.contextmanager + def mocked_timeout() -> Iterator[mock.Mock]: +- with mock.patch("urllib.request.urlopen") as urlopen_mock: ++ with mock.patch("urllib.request.build_opener") as build_opener_mock: ++ opener = mock.Mock() ++ build_opener_mock.return_value = opener ++ urlopen_mock = opener.open + urlopen_mock.side_effect = TimeoutError("timed out") + yield urlopen_mock + + + @contextlib.contextmanager + def mocked_http_error_response() -> Iterator[tuple[mock.Mock, HTTPError]]: +- with mock.patch("urllib.request.urlopen") as urlopen_mock: ++ with mock.patch("urllib.request.build_opener") as build_opener_mock: ++ opener = mock.Mock() ++ build_opener_mock.return_value = opener ++ urlopen_mock = opener.open + http_error = HTTPError( + url="https://example.com", + code=401, +@@ -105,6 +123,50 @@ def mocked_http_error_response() -> Iterator[tuple[mock.Mock, HTTPError]]: + + @crypto_required + class TestPyJWKClient: ++ def test_fetch_data_rejects_redirect_without_contacting_destination(self) -> None: ++ destination_requests = 0 ++ ++ class RedirectHandler(BaseHTTPRequestHandler): ++ def do_GET(self) -> None: # noqa: N802 - stdlib handler API ++ nonlocal destination_requests ++ if self.path == "/start": ++ self.send_response(302) ++ self.send_header("Location", f"{base_url}/destination") ++ self.end_headers() ++ else: ++ destination_requests += 1 ++ self.send_response(200) ++ self.end_headers() ++ ++ def log_message(self, _format: str, *args: object) -> None: ++ return ++ ++ server = ThreadingHTTPServer(("127.0.0.1", 0), RedirectHandler) ++ base_url = f"http://127.0.0.1:{server.server_port}" ++ thread = threading.Thread(target=server.serve_forever, daemon=True) ++ thread.start() ++ try: ++ client = PyJWKClient( ++ f"{base_url}/start", headers={"Authorization": "secret"} ++ ) ++ with pytest.raises(PyJWKClientConnectionError): ++ client.fetch_data() ++ assert destination_requests == 0 ++ finally: ++ server.shutdown() ++ server.server_close() ++ thread.join() ++ ++ def test_redirect_handler_does_not_follow_redirects(self) -> None: ++ handler = _NoRedirectHandler() ++ ++ assert ( ++ handler.redirect_request( ++ mock.Mock(), mock.Mock(), 302, "Found", {}, "https://other.test" ++ ) ++ is None ++ ) ++ + def test_fetch_data_forwards_headers_to_correct_url(self) -> None: + url = "https://dev-87evx9ru.auth0.com/.well-known/jwks.json" + +@@ -401,10 +463,19 @@ class TestPyJWKClient: + ssl_ctx = ssl.create_default_context() + jwks_client = PyJWKClient(url, ssl_context=ssl_ctx) + +- with mocked_success_response(RESPONSE_DATA_WITH_MATCHING_KID) as mock_request: ++ with mock.patch("urllib.request.build_opener") as build_opener_mock: ++ opener = mock.Mock() ++ build_opener_mock.return_value = opener ++ response = mock.Mock() ++ response.__enter__ = mock.Mock(return_value=response) ++ response.__exit__ = mock.Mock() ++ response.read.return_value = json.dumps(RESPONSE_DATA_WITH_MATCHING_KID) ++ opener.open.return_value = response + jwk_set = jwks_client.get_jwk_set() +- request_call = mock_request.call_args +- assert request_call[1].get("context") is ssl_ctx ++ handlers = build_opener_mock.call_args.args ++ assert any( ++ getattr(handler, "_context", None) is ssl_ctx for handler in handlers ++ ) + + assert jwk_set is not None + +@@ -414,8 +485,8 @@ class TestPyJWKClient: + url, ssl_context=ssl.SSLContext(protocol=ssl.PROTOCOL_TLS_CLIENT) + ) + +- with mock.patch("urllib.request.urlopen") as urlopen_mock: +- urlopen_mock.side_effect = URLError( ++ with mock.patch("urllib.request.build_opener") as build_opener_mock: ++ build_opener_mock.return_value.open.side_effect = URLError( + ssl.SSLCertVerificationError("certificate verify failed") + ) + with pytest.raises(PyJWKClientError): +-- +2.35.6 diff --git a/meta-python/recipes-devtools/python/python3-pyjwt_2.12.1.bb b/meta-python/recipes-devtools/python/python3-pyjwt_2.12.1.bb index a159f2fbbb..f7134a1367 100644 --- a/meta-python/recipes-devtools/python/python3-pyjwt_2.12.1.bb +++ b/meta-python/recipes-devtools/python/python3-pyjwt_2.12.1.bb @@ -13,6 +13,7 @@ SRC_URI += "file://CVE-2026-48522.patch \ file://CVE-2026-103001.patch \ file://CVE-2026-102274.patch \ file://CVE-2026-102269.patch \ + file://CVE-2026-102267.patch \ " SRC_URI[sha256sum] = "c74a7a2adf861c04d002db713dd85f84beb242228e671280bf709d765b03672b" From patchwork Fri Oct 16 02:33:18 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Hetvi Thakar -X (hthakar - E INFOCHIPS PRIVATE LIMITED at Cisco)" X-Patchwork-Id: 100924 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id 50163CCA462 for ; Fri, 16 Oct 2026 02:33:31 +0000 (UTC) Received: from rcdn-iport-5.cisco.com (rcdn-iport-5.cisco.com [173.37.86.76]) by mx.groups.io with SMTP id smtpd.msgproc02-g2.13506.1792118004428734226 for ; Thu, 15 Oct 2026 19:33:24 -0700 Authentication-Results: mx.groups.io; dkim=fail reason="dkim: message contains an insecure body length tag" header.i=@cisco.com header.s=iport01 header.b=QBN3GMSa; spf=pass (domain: cisco.com, ip: 173.37.86.76, mailfrom: hthakar@cisco.com) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=cisco.com; i=@cisco.com; l=5551; q=dns/txt; s=iport01; t=1792118004; x=1793327604; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=UgxjsWRJ5GmEVTZ0Q9T60bP9Es2SnpEK06jNw8wNMug=; b=QBN3GMSaQwxN42vyHyR9gIOeYbWrBBl+xIe2Y0j4iA4a9J5Tdqr7V3J4 IaCxROyJ0UQG3/iBQUMKm/bZ7ywYKfO4Gni2N3AIjCOaZ2iCqNNfnG0h1 assOHCKCpZAqI0fT1RaP2Ngg0c6IlGUarzc3dMlth0NNBVr+BMvC9Ic9L kmuU23e22/RR1x4MghTWlQLyuixQ9eF39tewLEcCnPdkrCaRyCIB0oOWx UX3ZEnP4hCAXXtVx09CEXvc+AL+LukNbXsimpChKUfXf4K6mmE5nNhqJg L/w13Z4HNRhA0nPcnmxK7s3IHRknXoBY5wNR87QU7xJlZX40azGwMRnzR g==; X-CSE-ConnectionGUID: bX/yDiyTQsCmXwud9A2MsQ== X-CSE-MsgGUID: FFxpXzHIS1uiunkV6lvmvw== X-IPAS-Result: A0BIAgBdi9Fq/47/Ja1aHgEBCxIMggULgld1YENJA5ZHA54cgX4PAQEBDzQdBAEBhD9GAo4VAiY0CQ4BAgQDAgMBAQEBAQEBAQEBAQEKAQEFAQEBAgEHBYEOE4ZPDZASAQIBAycLARgBLRAcAwECLysjCBmDAgGCdAMRBrxcgXkzgQGDKQGBVNsyAQsUAQWBM4VAiCNdGAGEfCcbG4FygRWDaYEFgVwBAQKIIwSCDRWBDIFahQ6QOUiBHgNZLAFVEw0KCwcFgWgDNRIqFW4yHYEjPheBBxsGBYEdgSCCFiMZNnqBCV6BKylgARAXgQmCBwKCVIIAAgFJQQ4HRVMJJUMSRyYiCBIJARMaMAuBGzg8CShBFwxzDB0FcggCDQkHKRgNSBEsNxUZBD5uB5ITHoI4KwIBgQ0BK0Y5EoEbDw+lV6EPCiiDdowilToaM4QEgVeSQJJUC5h9jgqWT4RpgWg8gVlwFYMiCUoZD44rDgscg0SFZMh2JzICCQMvAQEHAgcOAwuBaJF+AQE IronPort-Data: A9a23:9lcYTqO5QU/SQ3DvrR30lsFynXyQoLVcMsEvi/4bfWQNrUoj0TdUy GVOUTrSbKqOMDCjedAlbt/i9k5S7Z6GyYU1TXM5pCpnJ55oRWUpJjg4wmPYZX76whjrFRo/h ykmQoCeap1yFjmD9k/F3oHJ9RFUzbuPSqf3FNnKMyVwQR4MYCo6gHqPocZh6mJTqYb/WVzlV e/a+ZWFZgb9gmAsawr41orawP9RlKWq0N8nlgRWicBj5Df2i3QTBZQDEqC9R1OQapVUBOOzW 9HYx7i/+G7Dlz91Yj9yuu+mGqGiaue60Tmm0hK6aYD76vRxjnBaPpIACRYpQRw/ZwNlMDxG4 I4lWZSYEW/FN0BX8QgXe0Ew/ypWZcWq9FJbSJSymZT78qHIT5fj6/9eS1AaPJwkw/1cBFFR6 PBJAWoodSnW0opawJrjIgVtrt4oIM+uOMYUvWttiGmES/0nWpvEBa7N4Le03h9p2ZsIRqmYP ZdEL2MzNnwsYDUXUrsTIJIinO6rj2PXeDxDo1XTrq0yi4TW5FEqjuS3aoOIK7RmQ+17sFaAl nDm3l+gHxAHMt+hlz6b92yz07qncSTTHdh6+KeD3vlyjVuew2YeBBEbWR63rOe0jma6WslDM AoT4icooK04+UCnQ9W7WAe3yENopTYGUNZWVul/4waXx++MvkCSB3MPSXhKb9lOWNIKeAHGH 2Shx7vBbQGDepXMIZ5B3t94dQ+PBBU= IronPort-HdrOrdr: A9a23:m76Gj6utSHT0bPM+nGcAV0Hh7skDrtV00zEX/kB9WHVpmwKj+P xG+85rsiMc5wxxZJhNo7290ey7MBHhHP1OkO0s1MmZPDUO0VHAROoJ0WKh+UyEJ8SUzIBgPM lbH5SWIeeAa2SS9fyKgzWQIpIH3MSN9ryuiKP1yndgShwvVoRbhj0Jczpy1iZNNXJ77V1TLu vl2vZ6 X-Talos-CUID: 9a23:IUgUK20OoB2wLVwC4+IhRrxfEPBiY1Hc3UvpOGS9OXl0ROy8E3qLwfYx X-Talos-MUID: 9a23:7Bin2g+fu1rP8dCL6kqWHj6Qf+lG87yeGmAsqswbutSCNhIuPymYkiviFw== X-IronPort-Anti-Spam-Filtered: true X-IronPort-AV: E=Sophos;i="6.27,161,1787011200"; d="scan'208";a="536422159" Received: from rcdn-l-core-05.cisco.com ([173.37.255.142]) by rcdn-iport-5.cisco.com with ESMTP/TLS/TLS_AES_256_GCM_SHA384; 16 Oct 2026 02:33:23 +0000 Received: from sjc-ads-5245.cisco.com (sjc-ads-5245.cisco.com [10.28.23.9]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by rcdn-l-core-05.cisco.com (Postfix) with ESMTPS id 7978218000222; Fri, 16 Oct 2026 02:33:23 +0000 (GMT) Received: by sjc-ads-5245.cisco.com (Postfix, from userid 1887505) id C9971CBF21E; Thu, 15 Oct 2026 19:33:22 -0700 (PDT) From: "Hetvi Thakar -X (hthakar - E INFOCHIPS PRIVATE LIMITED at Cisco)" To: openembedded-devel@lists.openembedded.org Cc: xe-linux-external@cisco.com Subject: [meta-python][wrynose][PATCH 5/9] python3-pyjwt: fix CVE-2026-102268 and CVE-2026-102270 Date: Thu, 15 Oct 2026 19:33:18 -0700 Message-Id: <20261016023322.344365-6-hthakar@cisco.com> X-Mailer: git-send-email 2.35.6 In-Reply-To: <20261016023322.344365-1-hthakar@cisco.com> References: <20261016023322.344365-1-hthakar@cisco.com> MIME-Version: 1.0 X-Auto-Response-Suppress: DR, OOF, AutoReply X-Outbound-Client-TLS: ANONYMOUS;sjc-ads-5245.cisco.com [10.28.23.9];TLSv1.3;TLS_AES_256_GCM_SHA384;256 X-Outbound-SMTP-Client: 10.28.23.9, sjc-ads-5245.cisco.com X-Outbound-Node: rcdn-l-core-05.cisco.com List-Id: X-Webhook-Received: from 45-33-107-173.ip.linodeusercontent.com [45.33.107.173] by aws-us-west-2-korg-lkml-1.web.codeaurora.org with HTTPS for ; Fri, 16 Oct 2026 02:33:31 -0000 X-Groupsio-URL: https://lists.openembedded.org/g/openembedded-devel/message/131017 From: Hetvi Thakar This patch applies the shared upstream fix as referenced in [2] and [3], using the commit shown in [1]. [1] https://github.com/jpadilla/pyjwt/commit/8b4e233a22206b34ec1186e912e75c0b2396ac07 [2] https://github.com/jpadilla/pyjwt/security/advisories/GHSA-ffc3-869f-jxw9 [3] https://github.com/jpadilla/pyjwt/security/advisories/GHSA-jwrc-g2q2-pq5p Signed-off-by: Hetvi Thakar --- .../CVE-2026-102268_CVE-2026-102270.patch | 113 ++++++++++++++++++ .../python/python3-pyjwt_2.12.1.bb | 1 + 2 files changed, 114 insertions(+) create mode 100644 meta-python/recipes-devtools/python/files/CVE-2026-102268_CVE-2026-102270.patch diff --git a/meta-python/recipes-devtools/python/files/CVE-2026-102268_CVE-2026-102270.patch b/meta-python/recipes-devtools/python/files/CVE-2026-102268_CVE-2026-102270.patch new file mode 100644 index 0000000000..a845cb9065 --- /dev/null +++ b/meta-python/recipes-devtools/python/files/CVE-2026-102268_CVE-2026-102270.patch @@ -0,0 +1,113 @@ +From 8b4e233a22206b34ec1186e912e75c0b2396ac07 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jos=C3=A9=20Padilla?= +Date: Wed, 9 Sep 2026 21:49:21 -0400 +Subject: [PATCH] fix: reject loader-accepted PEM variants + +CVE: CVE-2026-102268 CVE-2026-102270 +Upstream-Status: Backport [https://github.com/jpadilla/pyjwt/commit/8b4e233a22206b34ec1186e912e75c0b2396ac07] + +(cherry picked from commit 8b4e233a22206b34ec1186e912e75c0b2396ac07) +Signed-off-by: Hetvi Thakar +--- + jwt/utils.py | 20 ++++++++++-------- + tests/test_algorithms.py | 44 +++++++++++++++++++++++++++++++++++++++- + 2 files changed, 55 insertions(+), 9 deletions(-) + +diff --git a/jwt/utils.py b/jwt/utils.py +index 56e89bb..914cb50 100644 +--- a/jwt/utils.py ++++ b/jwt/utils.py +@@ -113,18 +113,22 @@ _PEMS = { + b"X509 CRL", + } + +-_PEM_RE = re.compile( +- b"----[- ]BEGIN (" +- + b"|".join(_PEMS) +- + b""")[- ]----\r? +-.+?\r? +-----[- ]END \\1[- ]----\r?\n?""", +- re.DOTALL, ++# Accept PEM formatting variants that the cryptography loader accepts, while ++# retaining the explicit asymmetric-key marker check. ++_PEM_MARKER_RE = re.compile( ++ b"(?=(----[- ](BEGIN|END) (" + b"|".join(_PEMS) + b")[- ]----))" + ) + + + def is_pem_format(key: bytes) -> bool: +- return bool(_PEM_RE.search(key)) ++ begin_markers: dict[bytes, int] = {} ++ for marker in _PEM_MARKER_RE.finditer(key): ++ marker_type, label = marker.group(2), marker.group(3) ++ if marker_type == b"BEGIN": ++ begin_markers[label] = marker.start(1) + len(marker.group(1)) ++ elif label in begin_markers and begin_markers[label] < marker.start(1): ++ return True ++ return False + + + # Based on https://github.com/pyca/cryptography/blob/bcb70852d577b3f490f015378c75cba74986297b/src/cryptography/hazmat/primitives/serialization/ssh.py#L40-L46 +diff --git a/tests/test_algorithms.py b/tests/test_algorithms.py +index 82659cf..4e149a7 100644 +--- a/tests/test_algorithms.py ++++ b/tests/test_algorithms.py +@@ -1,6 +1,6 @@ + import base64 + import json +-from typing import Union, cast ++from typing import Callable, Union, cast + + import pytest + +@@ -89,6 +89,48 @@ class TestAlgorithms: + with open(key_path(key)) as keyfile: + algo.prepare_key(keyfile.read()) + ++ @pytest.mark.parametrize( ++ "mutation", ++ [ ++ lambda key: key.replace(b"-----END", b"\t-----END"), ++ lambda key: key.replace(b"\n", b"\r"), ++ lambda key: key.replace(b"\n", b""), ++ ], ++ ) ++ def test_hmac_should_reject_loader_accepted_pem_mutations( ++ self, mutation: Callable[[bytes], bytes] ++ ) -> None: ++ algo = HMACAlgorithm(HMACAlgorithm.SHA256) ++ with open(key_path("testkey2_rsa.pub.pem"), "rb") as keyfile: ++ mutated_key = mutation(keyfile.read()) ++ ++ with pytest.raises(InvalidKeyError): ++ algo.prepare_key(mutated_key) ++ ++ def test_hmac_should_accept_incomplete_pem_marker(self) -> None: ++ algo = HMACAlgorithm(HMACAlgorithm.SHA256) ++ key = b"-----BEGIN PUBLIC KEY-----" * 10000 ++ ++ assert algo.prepare_key(key) == key ++ ++ def test_hmac_should_reject_a_later_pem_block(self) -> None: ++ algo = HMACAlgorithm(HMACAlgorithm.SHA256) ++ with open(key_path("testkey2_rsa.pub.pem"), "rb") as keyfile: ++ key = b"-----BEGIN PUBLIC KEY-----" + keyfile.read() ++ ++ with pytest.raises(InvalidKeyError): ++ algo.prepare_key(key) ++ ++ def test_hmac_should_reject_a_pem_block_after_an_overlapping_end_marker( ++ self, ++ ) -> None: ++ algo = HMACAlgorithm(HMACAlgorithm.SHA256) ++ with open(key_path("testkey2_rsa.pub.pem"), "rb") as keyfile: ++ key = b"-----END CERTIFICATE" + keyfile.read() ++ ++ with pytest.raises(InvalidKeyError): ++ algo.prepare_key(key) ++ + def test_hmac_jwk_should_parse_and_verify(self) -> None: + algo = HMACAlgorithm(HMACAlgorithm.SHA256) + +-- +2.35.6 diff --git a/meta-python/recipes-devtools/python/python3-pyjwt_2.12.1.bb b/meta-python/recipes-devtools/python/python3-pyjwt_2.12.1.bb index f7134a1367..b93806fe48 100644 --- a/meta-python/recipes-devtools/python/python3-pyjwt_2.12.1.bb +++ b/meta-python/recipes-devtools/python/python3-pyjwt_2.12.1.bb @@ -14,6 +14,7 @@ SRC_URI += "file://CVE-2026-48522.patch \ file://CVE-2026-102274.patch \ file://CVE-2026-102269.patch \ file://CVE-2026-102267.patch \ + file://CVE-2026-102268_CVE-2026-102270.patch \ " SRC_URI[sha256sum] = "c74a7a2adf861c04d002db713dd85f84beb242228e671280bf709d765b03672b" From patchwork Fri Oct 16 02:33:19 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Hetvi Thakar -X (hthakar - E INFOCHIPS PRIVATE LIMITED at Cisco)" X-Patchwork-Id: 100923 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id 77EDFCCA46B for ; Fri, 16 Oct 2026 02:33:31 +0000 (UTC) Received: from rcdn-iport-4.cisco.com (rcdn-iport-4.cisco.com [173.37.86.75]) by mx.groups.io with SMTP id smtpd.msgproc01-g2.13367.1792118004529976392 for ; Thu, 15 Oct 2026 19:33:24 -0700 Authentication-Results: mx.groups.io; dkim=fail reason="dkim: message contains an insecure body length tag" header.i=@cisco.com header.s=iport01 header.b=HDk+4Kbu; spf=pass (domain: cisco.com, ip: 173.37.86.75, mailfrom: hthakar@cisco.com) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=cisco.com; i=@cisco.com; l=6037; q=dns/txt; s=iport01; t=1792118004; x=1793327604; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=4QkVMfNcFDSXOpm7b1nBW4V+jTzeqZ+5wZoqRNuKrz0=; b=HDk+4KbuEwR/wydtjmZJ+k+5u3WK/dTZPxA1yqaBY1lPQioMOlQa98D0 ET5NKQOwTrnV/Q4torZBLzOuyGd0H1HwUFnxnyQfEEjJ5nwT1mP7wZhMo nlFkIP927Sa4JKCu72ZDvhKZLNApcM9C8HL3kB9GCNpD17ks08TY/ZNAG Ju9dRwLWVLndJ3am5B0MvpDx3Lv+s+HYNdpcQaM5p43vguIByMH6TCacN +nR35LvWDVdB5FmKcDluXUP4lEuGXcHcrb33yQvfaYh/1w8UEFsrCFrL3 pgcJ9VLjlnKq22bpzCQa/flrr6gdbbQioSNYTiOviUH2hA/vBH4PTsK7G w==; X-CSE-ConnectionGUID: XA3wdq6nT3+HlfdprF7ypg== X-CSE-MsgGUID: Te9wRqt+SoO7W8qsnEsZxg== X-IPAS-Result: A0BIAgDZi9Fq/5L/Ja1aglmCV3VgQ0kDlkcDnhyBfg8BAQEPRA0EAQGFBQKOFQImNAkOAQIEAwIDAQEBAQEBAQEBAQEBCgEBBQEBAQIBBwWBDhOGTw2QEgECAQMnCwEYAS0QHAMBAi8rIwgZgwIBgnQDEbxngXkzgQGDKQGBVNsyAQsUAQWBM4VAiCNdGAFEhDgnGxuBcoEVg2mBBYFcAoEnhn4EgiKBDIFalUdIgR4DWSwBVRMNCgsHBYFoAzUSKhVuMh2BIz4XgQcbBgWBHYEgghYjGTZ6gQlegSspYAEQF4EJggcCglSCAAIBSUEOB0VTCSVDEkcmIggSCQETGjALgRs4PAkoQRcMcwwdBXIIAg0JBykYDUgRLDcVGQQ+bgeSEx6CYwKBDgErfxIPgQwepVeMAJUPCiiDdowilToaM4QEgVeSQJJUC5h9jgqWBUqEaYFoPIFZcBWDIglKGQ+OKw4Lg2CFZMh2JzICAQgDLwEBBwIHDgMLgWiQAIF+AQE IronPort-Data: A9a23:Uhvq/aiv0CTRP07VGms3rSDMX161MREKZh0ujC45NGQN5FlHY01je htvUGCOPvbcYGWkc9p1boi390oG68OHm4BlQAVtqyhjE3tjpJueD7x1DKtf0wB+jyHnZBg6h ynLQoCYdKjYdleF+FHwdOCn8ikkvU2xbuKUIPbePSxsThNTRi4kiBZy88Y0mYcAbeKRW2thg vus5ZeAULOZ82QsaDxNs/vd8EoHUMna4Vv0gHRvPZing3eG/5UlJMp3Db28KXL+Xr5VEoaSL 87fzKu093/u5BwkDNWoiN7TKiXmlZaLYGBiIlIPM0STqkAqSh4ai87XB9JAAatjsAhlqvgqo Dl7WTNcfi9yVkHEsLx1vxC1iEiSN4UekFPMCSDXXcB+UyQqflO0q8iCAn3aMqUo071oDXgQ8 8BDaxAJYBybnczp0aq0H7wEasQLdKEHPasFsX1miDWcBvE8TNWbEuPB5MRT23E7gcUm8fT2P pVCL2EwKk6dPlsWZgl/5JEWxI9EglH/bz1Rq1uPjaE2+GPUigd21dABNfKIIYLTFZ0Jxx/wS mTuw2moHSsDKJ+kzh3azSK1nenihhHrV9dHfFG/3rsw6LGJ/UQUEBAQWF6xrPW1h0L7V99BJ kg8/is1sbN081SmSNT4VRC0rHOI+BkGVLJt//YS8gqBzO/Qpg2eHGVBFm8HY909v8hwTjsvv rOUo+7U6fVUmOX9YRqgGn2891te5QB9wbc+WBI5 IronPort-HdrOrdr: A9a23:B7KsOaD2OgK4PMflHel055DYdb4zR+YMi2TDGXofdfUzSL3+qy nAppUmPHPP5Qr5HUtQ++xoW5PwJU80i6QU3WB5B97LN2PbUSmTXeRfBODZrQEIdReTygd179 YHT0EHMqySMXFKyeDn/QK/D9EshPOD8KyumKPi6k0Fd3ASV0mlhD0JcTpy1SZNNXF7OaY= X-Talos-CUID: 9a23:lF9Ol2PrzROZdu5DaAA860INRMYZKT79yHncO1WWVndxR+jA X-Talos-MUID: 9a23:7hPz6AaBjl6hoeBTizK9mwt7KIRT5IPxNxAUipMroPuUOnkl X-IronPort-Anti-Spam-Filtered: true X-IronPort-AV: E=Sophos;i="6.27,161,1787011200"; d="scan'208";a="536180411" Received: from rcdn-l-core-09.cisco.com ([173.37.255.146]) by rcdn-iport-4.cisco.com with ESMTP/TLS/TLS_AES_256_GCM_SHA384; 16 Oct 2026 02:33:23 +0000 Received: from sjc-ads-5245.cisco.com (sjc-ads-5245.cisco.com [10.28.23.9]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by rcdn-l-core-09.cisco.com (Postfix) with ESMTPS id 7A79C1800048E; Fri, 16 Oct 2026 02:33:23 +0000 (GMT) Received: by sjc-ads-5245.cisco.com (Postfix, from userid 1887505) id CD867CBEF8A; Thu, 15 Oct 2026 19:33:22 -0700 (PDT) From: "Hetvi Thakar -X (hthakar - E INFOCHIPS PRIVATE LIMITED at Cisco)" To: openembedded-devel@lists.openembedded.org Cc: xe-linux-external@cisco.com Subject: [meta-python][wrynose][PATCH 6/9] python3-pyjwt: fix CVE-2026-102271 Date: Thu, 15 Oct 2026 19:33:19 -0700 Message-Id: <20261016023322.344365-7-hthakar@cisco.com> X-Mailer: git-send-email 2.35.6 In-Reply-To: <20261016023322.344365-1-hthakar@cisco.com> References: <20261016023322.344365-1-hthakar@cisco.com> MIME-Version: 1.0 X-Auto-Response-Suppress: DR, OOF, AutoReply X-Outbound-Client-TLS: ANONYMOUS;sjc-ads-5245.cisco.com [10.28.23.9];TLSv1.3;TLS_AES_256_GCM_SHA384;256 X-Outbound-SMTP-Client: 10.28.23.9, sjc-ads-5245.cisco.com X-Outbound-Node: rcdn-l-core-09.cisco.com List-Id: X-Webhook-Received: from 45-33-107-173.ip.linodeusercontent.com [45.33.107.173] by aws-us-west-2-korg-lkml-1.web.codeaurora.org with HTTPS for ; Fri, 16 Oct 2026 02:33:31 -0000 X-Groupsio-URL: https://lists.openembedded.org/g/openembedded-devel/message/131018 From: Hetvi Thakar This patch applies the upstream fix as referenced in [2], using the commit shown in [1]. [1] https://github.com/jpadilla/pyjwt/commit/2798504fa2663364573cf2d1043d8d7fef389499 [2] https://github.com/jpadilla/pyjwt/security/advisories/GHSA-p4g4-x82p-q773 Signed-off-by: Hetvi Thakar --- .../python/files/CVE-2026-102271.patch | 136 ++++++++++++++++++ .../python/python3-pyjwt_2.12.1.bb | 1 + 2 files changed, 137 insertions(+) create mode 100644 meta-python/recipes-devtools/python/files/CVE-2026-102271.patch diff --git a/meta-python/recipes-devtools/python/files/CVE-2026-102271.patch b/meta-python/recipes-devtools/python/files/CVE-2026-102271.patch new file mode 100644 index 0000000000..c6e255d62b --- /dev/null +++ b/meta-python/recipes-devtools/python/files/CVE-2026-102271.patch @@ -0,0 +1,136 @@ +From 2798504fa2663364573cf2d1043d8d7fef389499 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jos=C3=A9=20Padilla?= +Date: Thu, 10 Sep 2026 08:33:25 -0400 +Subject: [PATCH] fix: reject DER public keys as HMAC secrets + +CVE: CVE-2026-102271 +Upstream-Status: Backport [https://github.com/jpadilla/pyjwt/commit/2798504fa2663364573cf2d1043d8d7fef389499] + +(cherry picked from commit 2798504fa2663364573cf2d1043d8d7fef389499) +Signed-off-by: Hetvi Thakar +--- + jwt/algorithms.py | 27 ++++++++++++++++++++++++++- + tests/test_algorithms.py | 39 +++++++++++++++++++++++++++++++++++++++ + 2 files changed, 65 insertions(+), 1 deletion(-) + +diff --git a/jwt/algorithms.py b/jwt/algorithms.py +index cf6da45..432fdcf 100644 +--- a/jwt/algorithms.py ++++ b/jwt/algorithms.py +@@ -33,6 +33,7 @@ from .utils import ( + ) + + try: ++ from cryptography import x509 + from cryptography.exceptions import InvalidSignature, UnsupportedAlgorithm + from cryptography.hazmat.backends import default_backend + from cryptography.hazmat.primitives import hashes +@@ -72,6 +73,7 @@ try: + NoEncryption, + PrivateFormat, + PublicFormat, ++ load_der_public_key, + load_pem_private_key, + load_pem_public_key, + load_ssh_public_key, +@@ -322,10 +324,33 @@ class HMACAlgorithm(Algorithm): + def __init__(self, hash_alg: HashlibHash) -> None: + self.hash_alg = hash_alg + ++ @staticmethod ++ def _is_der_key(key_bytes: bytes) -> bool: ++ if not has_crypto: ++ return False ++ ++ try: ++ load_der_public_key(key_bytes) ++ except (TypeError, ValueError, UnsupportedAlgorithm): ++ pass ++ else: ++ return True ++ ++ try: ++ x509.load_der_x509_certificate(key_bytes) ++ except (TypeError, ValueError, UnsupportedAlgorithm): ++ return False ++ else: ++ return True ++ + def prepare_key(self, key: str | bytes) -> bytes: + key_bytes = force_bytes(key) + +- if is_pem_format(key_bytes) or is_ssh_key(key_bytes): ++ if ( ++ is_pem_format(key_bytes) ++ or is_ssh_key(key_bytes) ++ or self._is_der_key(key_bytes) ++ ): + raise InvalidKeyError( + "The specified key is an asymmetric key or x509 certificate and" + " should not be used as an HMAC secret." +diff --git a/tests/test_algorithms.py b/tests/test_algorithms.py +index 4e149a7..acaa1fe 100644 +--- a/tests/test_algorithms.py ++++ b/tests/test_algorithms.py +@@ -12,6 +12,7 @@ from .keys import load_ec_pub_key_p_521, load_hmac_key, load_rsa_pub_key + from .utils import crypto_required, key_path + + if has_crypto: ++ from cryptography import x509 + from cryptography.hazmat.primitives.asymmetric.ec import ( + EllipticCurvePrivateKey, + EllipticCurvePublicKey, +@@ -28,6 +29,10 @@ if has_crypto: + RSAPrivateKey, + RSAPublicKey, + ) ++ from cryptography.hazmat.primitives.serialization import ( ++ Encoding, ++ PublicFormat, ++ ) + + from jwt.algorithms import ECAlgorithm, OKPAlgorithm, RSAAlgorithm, RSAPSSAlgorithm + +@@ -187,6 +192,40 @@ class TestAlgorithms: + key = algo.prepare_key('{"this": "is just a json-shaped secret"}') + assert key == b'{"this": "is just a json-shaped secret"}' + ++ @crypto_required ++ @pytest.mark.parametrize( ++ "key_format_name", ++ ("SubjectPublicKeyInfo", "PKCS1"), ++ ) ++ def test_hmac_prepare_key_rejects_der_public_key( ++ self, key_format_name: str ++ ) -> None: ++ algo = HMACAlgorithm(HMACAlgorithm.SHA256) ++ public_key = cast(RSAPublicKey, load_rsa_pub_key()) ++ der_key = public_key.public_bytes( ++ Encoding.DER, getattr(PublicFormat, key_format_name) ++ ) ++ ++ with pytest.raises(InvalidKeyError, match="asymmetric key"): ++ algo.prepare_key(der_key) ++ ++ @crypto_required ++ def test_hmac_prepare_key_rejects_der_certificate(self) -> None: ++ algo = HMACAlgorithm(HMACAlgorithm.SHA256) ++ with open(key_path("testkey_rsa.cer"), "rb") as certificate_file: ++ certificate = x509.load_pem_x509_certificate(certificate_file.read()) ++ der_certificate = certificate.public_bytes(Encoding.DER) ++ ++ with pytest.raises(InvalidKeyError, match="x509 certificate"): ++ algo.prepare_key(der_certificate) ++ ++ @crypto_required ++ def test_hmac_prepare_key_accepts_non_key_binary_secret(self) -> None: ++ algo = HMACAlgorithm(HMACAlgorithm.SHA256) ++ secret = b"\x30\x82not-a-der-key" ++ ++ assert algo.prepare_key(secret) == secret ++ + @crypto_required + def test_rsa_should_parse_pem_public_key(self) -> None: + algo = RSAAlgorithm(RSAAlgorithm.SHA256) +-- +2.35.6 diff --git a/meta-python/recipes-devtools/python/python3-pyjwt_2.12.1.bb b/meta-python/recipes-devtools/python/python3-pyjwt_2.12.1.bb index b93806fe48..cd91139d58 100644 --- a/meta-python/recipes-devtools/python/python3-pyjwt_2.12.1.bb +++ b/meta-python/recipes-devtools/python/python3-pyjwt_2.12.1.bb @@ -15,6 +15,7 @@ SRC_URI += "file://CVE-2026-48522.patch \ file://CVE-2026-102269.patch \ file://CVE-2026-102267.patch \ file://CVE-2026-102268_CVE-2026-102270.patch \ + file://CVE-2026-102271.patch \ " SRC_URI[sha256sum] = "c74a7a2adf861c04d002db713dd85f84beb242228e671280bf709d765b03672b" From patchwork Fri Oct 16 02:33:20 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: "Hetvi Thakar -X (hthakar - E INFOCHIPS PRIVATE LIMITED at Cisco)" X-Patchwork-Id: 100927 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id AF7D6CCA490 for ; Fri, 16 Oct 2026 02:33:31 +0000 (UTC) Received: from rcdn-iport-2.cisco.com (rcdn-iport-2.cisco.com [173.37.86.73]) by mx.groups.io with SMTP id smtpd.msgproc02-g2.13504.1792118004184969055 for ; Thu, 15 Oct 2026 19:33:25 -0700 Authentication-Results: mx.groups.io; dkim=fail reason="dkim: message contains an insecure body length tag" header.i=@cisco.com header.s=iport01 header.b=YVht/R0D; spf=pass (domain: cisco.com, ip: 173.37.86.73, mailfrom: hthakar@cisco.com) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=cisco.com; i=@cisco.com; l=12827; q=dns/txt; s=iport01; t=1792118004; x=1793327604; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=brzBJCWsfFd81JGtV8Q5JlvVKHMjPCNxbgyi8eZt13k=; b=YVht/R0DvGX7Ja7tvJJAKwVCCW3qmfe7CmMUwXrSDZz8Y5d4zio/Idgl itcYtq3rABNuTiCDQRMtV+/19lU3tpTPwkI/IgeaV3VKl3oiFC2pXnNAB xT7jWOEMAdd/lvd0pKQijUgf8KojvR1QOk9NRxkIk5Z0HdwV4Rg5Vf0b7 PUwArhGsghrDEm7f+6Daqlsl4RNur2PVvnVlc7eH43jSW83qUuLx9g/Zp HCJBUVX9oTiX2WWAy8ljAQtrzSpypK7pnKQlOA49TgQ04GtscOSRdqzJk UhOMUjUa05ANlwWgZIPAZ6WiEpJdWzQJ6SianP8PHUDadmjaTmtLO2GBC Q==; X-CSE-ConnectionGUID: 5uvOfY0kQUaUsUYXlAyjzQ== X-CSE-MsgGUID: Ij7QEX1zSXimiA7jGAkcig== X-IPAS-Result: A0AnAADZi9Fq/43/Ja1aEwEBCAEBAQEJARIBBQUBgXwIAQsBghc/dWBDSQOEVIgbiVgDgROdCYF+DwEBAQ9EDQQBAYUFAo4VAiY0CQ4BAgQDAgMBAQEBAQEBAQEBAQEKAQEFAQEBAgEHBYEOE4ZPDZASAQIBAyMECwEYAS0QHAMBAgMCJgICKyMIGYIqWAGCdAMRBrxhen8zgQGDKQGBVNsyAQsUAQWBBS4BhT+DHwGFA10YAUSEOCcbG4FygRWCc3aBBYFcAoU7gmoEgiKBDIFagQOUREiBAhwDWSwBVRMNCgsHBYFoAzUSKhVuMh2BIz4XL1gbBgWBHYEgghYjGTZ6gQlegSspYAEQF4EJggcCglSCAAIBSUEOB0VTCSVDEkcmIggSCQETGjALgRs4PAkoQRcMcwwdBXIIAg0JBykYDUgRLDcVGQQ9AW4HkhMegmU9HAEhBg0BCSJIKQ4SgRsepVehDwoog3aMIpU6GjOEBJQXklQLmH2OCoFNlAgqUIRpgWg8gVlwFTuCZwlKGQ+OKwMLC4NgzlonMgIJAy8BAQcCBw4DC4FokR5gAQE IronPort-Data: A9a23:ZlC5Bq4acnQF7uYOAjjA9gxRtGnGchMFZxGqfqrLsTDasY5as4F+v mcdWj2GbPaPazD1Lo9yPYW39RtSu5GAmIdmQQRrrn00Zn8b8sCt6fZ1gavT04J+CuWZESqLO u1HMoGowPgcFyGa+1H1dOex9RGQ7InQLpLkEunIJyttcgFtTSYlmHpLlvUw6mJSqYDR7zil5 5Wo/KUzBHf/g2QqazpNtfrawP9SlK2aVA0w7wRWic9j5Dcyp1FNZLoDKKe4KWfPQ4U8NoaSW +bZwbilyXjS9hErB8nNuu6TnpoiG+O60aCm0xK6aoD66vRwjnVaPpUTaJLwXXxqZwChxLid/ jniWauYEm/FNoWU8AgUvoIx/ytWZcWq85efSZSzXFD6I0DuKxPRL/tS4E4eYJAG3ehGWWJ3y PUlMw08XhSqluCk+efuIgVsrpxLwMjDJogTvDRkiDreF/tjGcyFSKTR7tge1zA17ixMNa+BP IxCNnw1MUmGOkEWUrsUIMpWcOOAhmX/ej5RsnqepLE85C7YywkZPL3FbYCMK4HUHJUK9qqej kPEoF3UMkgID+yezDusrXCDr+zEnCyuDer+E5X9rJaGmma7wXQeDhATX1a3rfS1z0KzRd9bA 0gV4TY1668q+UqmS9PwUxG1rDiDpBF0ZjZLO/cx5AfIzu/f5ByUQzBYCDVAc9ch8sQxQFTGy 2O0oj8gPhQ32JX9dJ5X3u38Qe+aUcTNEVI/WA== IronPort-HdrOrdr: A9a23:SrHVwqPghn06hMBcTh+jsMiBIKoaSvp037Dk7S9MoHtuA6qlfq GV7ZMmPHDP6Qr5NEtMpTnEAtjjfZq+z+8Q3WBuB9eftWDd0QPCRr2Kr7GSpgEIcBeRygcy78 tdmoFFeaTN5CBB/KXHyTj9Nco8y9+a963tr+Lfw3BxCTxOUchbnn9E4sLxKDwNeOGAbqBJb6 ah2g== X-Talos-CUID: 9a23:clB8wG8oiCQ/DAs0FeGVvxMJBOcrQyXe9UrZHlSFOFZtYayXW2bFrQ== X-Talos-MUID: 9a23:awjOoQ9CprdbVcJqECF+SiqQf+ZqvJ2DOBkfqqUHvsitai5fEjSWjTviFw== X-IronPort-Anti-Spam-Filtered: true X-IronPort-AV: E=Sophos;i="6.27,161,1787011200"; d="scan'208";a="521956187" Received: from rcdn-l-core-04.cisco.com ([173.37.255.141]) by rcdn-iport-2.cisco.com with ESMTP/TLS/TLS_AES_256_GCM_SHA384; 16 Oct 2026 02:33:23 +0000 Received: from sjc-ads-5245.cisco.com (sjc-ads-5245.cisco.com [10.28.23.9]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by rcdn-l-core-04.cisco.com (Postfix) with ESMTPS id 7A78F18000191; Fri, 16 Oct 2026 02:33:23 +0000 (GMT) Received: by sjc-ads-5245.cisco.com (Postfix, from userid 1887505) id D13AECBEF98; Thu, 15 Oct 2026 19:33:22 -0700 (PDT) From: "Hetvi Thakar -X (hthakar - E INFOCHIPS PRIVATE LIMITED at Cisco)" To: openembedded-devel@lists.openembedded.org Cc: xe-linux-external@cisco.com Subject: [meta-python][wrynose][PATCH 7/9] python3-pyjwt: fix CVE-2026-101917 Date: Thu, 15 Oct 2026 19:33:20 -0700 Message-Id: <20261016023322.344365-8-hthakar@cisco.com> X-Mailer: git-send-email 2.35.6 In-Reply-To: <20261016023322.344365-1-hthakar@cisco.com> References: <20261016023322.344365-1-hthakar@cisco.com> MIME-Version: 1.0 X-Auto-Response-Suppress: DR, OOF, AutoReply X-Outbound-Client-TLS: ANONYMOUS;sjc-ads-5245.cisco.com [10.28.23.9];TLSv1.3;TLS_AES_256_GCM_SHA384;256 X-Outbound-SMTP-Client: 10.28.23.9, sjc-ads-5245.cisco.com X-Outbound-Node: rcdn-l-core-04.cisco.com List-Id: X-Webhook-Received: from 45-33-107-173.ip.linodeusercontent.com [45.33.107.173] by aws-us-west-2-korg-lkml-1.web.codeaurora.org with HTTPS for ; Fri, 16 Oct 2026 02:33:31 -0000 X-Groupsio-URL: https://lists.openembedded.org/g/openembedded-devel/message/131021 From: Hetvi Thakar This patch applies the upstream fix as referenced in [2], using the commit shown in [1]. [1] https://github.com/jpadilla/pyjwt/commit/ba4853a75fb9676362da17f67d0f64bd18afd4e1 [2] https://github.com/jpadilla/pyjwt/security/advisories/GHSA-2gx3-rcp4-g85q Signed-off-by: Hetvi Thakar --- .../python/files/CVE-2026-101917.patch | 311 ++++++++++++++++++ .../python/python3-pyjwt_2.12.1.bb | 1 + 2 files changed, 312 insertions(+) create mode 100644 meta-python/recipes-devtools/python/files/CVE-2026-101917.patch diff --git a/meta-python/recipes-devtools/python/files/CVE-2026-101917.patch b/meta-python/recipes-devtools/python/files/CVE-2026-101917.patch new file mode 100644 index 0000000000..e9e730ea7e --- /dev/null +++ b/meta-python/recipes-devtools/python/files/CVE-2026-101917.patch @@ -0,0 +1,311 @@ +From ba4853a75fb9676362da17f67d0f64bd18afd4e1 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jos=C3=A9=20Padilla?= +Date: Thu, 10 Sep 2026 14:10:52 -0400 +Subject: [PATCH] Throttle repeated PyJWKClient refreshes + +CVE: CVE-2026-101917 +Upstream-Status: Backport [https://github.com/jpadilla/pyjwt/commit/ba4853a75fb9676362da17f67d0f64bd18afd4e1] + +(cherry picked from commit ba4853a75fb9676362da17f67d0f64bd18afd4e1) +Signed-off-by: Hetvi Thakar +--- + jwt/jwks_client.py | 63 ++++++++++++++--- + tests/test_jwks_client.py | 141 +++++++++++++++++++++++++++++++++++++- + 2 files changed, 192 insertions(+), 12 deletions(-) + +diff --git a/jwt/jwks_client.py b/jwt/jwks_client.py +index cfc9003..dcf1edd 100644 +--- a/jwt/jwks_client.py ++++ b/jwt/jwks_client.py +@@ -1,6 +1,9 @@ + from __future__ import annotations + + import json ++import math ++import threading ++import time + import urllib.request + from functools import lru_cache + from ssl import SSLContext +@@ -38,6 +41,7 @@ class PyJWKClient: + headers: dict[str, Any] | None = None, + timeout: float = 30, + ssl_context: SSLContext | None = None, ++ cooldown_duration: float = 30, + ): + """A client for retrieving signing keys from a JWKS endpoint. + +@@ -54,6 +58,14 @@ class PyJWKClient: + - ``lifespan``: Time in seconds before the cached JWK Set expires. + Defaults to ``300`` (5 minutes). Must be greater than 0. + ++ Unknown key IDs can trigger one forced refresh after the cooldown ++ period configured by ``cooldown_duration``. Every successful fetch ++ starts this cooldown, including the initial fetch and cache-expiry ++ fetches. A newly rotated key may therefore wait for the cooldown ++ period before it is fetched; set ``cooldown_duration`` to ``0`` to ++ disable this behavior. The cooldown is bypassed when ++ ``cache_jwk_set`` is ``False``. ++ + **Tier 2 — Signing key cache** (disabled by default): + Caches individual signing keys (looked up by ``kid``) using an LRU + cache with **no time-based expiration**. Keys are evicted only when +@@ -80,6 +92,9 @@ class PyJWKClient: + :type timeout: float + :param ssl_context: Optional SSL context for the request. + :type ssl_context: ssl.SSLContext or None ++ :param cooldown_duration: Minimum time in seconds between forced ++ refreshes after an unknown key ID. Defaults to ``30``. ++ :type cooldown_duration: float + """ + if headers is None: + headers = {} +@@ -98,6 +113,18 @@ class PyJWKClient: + self.headers = headers + self.timeout = timeout + self.ssl_context = ssl_context ++ if cooldown_duration < 0: ++ raise PyJWKClientError( ++ "Cooldown duration must be greater than or equal to 0, " ++ f'the input is "{cooldown_duration}"' ++ ) ++ if not math.isfinite(cooldown_duration): ++ raise PyJWKClientError( ++ f'Cooldown duration must be finite, the input is "{cooldown_duration}"' ++ ) ++ self.cooldown_duration = cooldown_duration ++ self._last_successful_fetch: float | None = None ++ self._client_lock = threading.RLock() + + if cache_jwk_set: + # Init jwt set cache with default or given lifespan. +@@ -147,6 +174,7 @@ class PyJWKClient: + # wipe that breaks legitimate auth. + if self.jwk_set_cache is not None: + self.jwk_set_cache.put(jwk_set) ++ self._last_successful_fetch = time.monotonic() + return jwk_set + + def get_jwk_set(self, refresh: bool = False) -> PyJWKSet: +@@ -186,6 +214,10 @@ class PyJWKClient: + :raises PyJWKClientError: If no signing keys are found. + """ + jwk_set = self.get_jwk_set(refresh) ++ return self._get_signing_keys_from_jwk_set(jwk_set) ++ ++ @staticmethod ++ def _get_signing_keys_from_jwk_set(jwk_set: PyJWKSet) -> list[PyJWK]: + signing_keys = [ + jwk_set_key + for jwk_set_key in jwk_set.keys +@@ -200,8 +232,9 @@ class PyJWKClient: + def get_signing_key(self, kid: str) -> PyJWK: + """Return the signing key matching the given ``kid``. + +- If no match is found in the current JWK Set, the set is +- refreshed from the endpoint and the lookup is retried once. ++ If no match is found in the current JWK Set, the set is refreshed ++ from the endpoint and the lookup is retried once when the refresh ++ cooldown permits it. + + :param kid: The key ID to look up. + :type kid: str +@@ -210,20 +243,28 @@ class PyJWKClient: + :raises PyJWKClientError: If no matching key is found after + refreshing. + """ +- signing_keys = self.get_signing_keys() +- signing_key = self.match_kid(signing_keys, kid) +- +- if not signing_key: +- # If no matching signing key from the jwk set, refresh the jwk set and try again. +- signing_keys = self.get_signing_keys(refresh=True) ++ with self._client_lock: ++ signing_keys = self.get_signing_keys() + signing_key = self.match_kid(signing_keys, kid) + + if not signing_key: +- raise PyJWKClientError( +- f'Unable to find a signing key that matches: "{kid}"' ++ cooling_down = ( ++ self.jwk_set_cache is not None ++ and self._last_successful_fetch is not None ++ and time.monotonic() - self._last_successful_fetch ++ < self.cooldown_duration + ) ++ if not cooling_down: ++ signing_keys = self.get_signing_keys(refresh=True) ++ self._last_successful_fetch = time.monotonic() ++ signing_key = self.match_kid(signing_keys, kid) + +- return signing_key ++ if not signing_key: ++ raise PyJWKClientError( ++ f'Unable to find a signing key that matches: "{kid}"' ++ ) ++ ++ return signing_key + + def get_signing_key_from_jwt(self, token: str | bytes) -> PyJWK: + """Return the signing key for a JWT by reading its ``kid`` header. +diff --git a/tests/test_jwks_client.py b/tests/test_jwks_client.py +index 49471ac..c66dfd7 100644 +--- a/tests/test_jwks_client.py ++++ b/tests/test_jwks_client.py +@@ -386,7 +386,7 @@ class TestPyJWKClient: + + def test_get_jwt_set_refresh_cache(self) -> None: + url = "https://dev-87evx9ru.auth0.com/.well-known/jwks.json" +- jwks_client = PyJWKClient(url) ++ jwks_client = PyJWKClient(url, cooldown_duration=0) + + kid = "NEE1QURBOTM4MzI5RkFDNTYxOTU1MDg2ODgwQ0UzMTk1QjYyRkRFQw" + +@@ -411,6 +411,145 @@ class TestPyJWKClient: + ): + jwks_client.get_signing_key(kid) + ++ def test_unknown_kid_refresh_is_cooled_down(self) -> None: ++ url = "https://dev-87evx9ru.auth0.com/.well-known/jwks.json" ++ kid = "unknown-kid" ++ jwks_client = PyJWKClient(url, cooldown_duration=30) ++ ++ with mock.patch("urllib.request.build_opener") as build_opener_mock: ++ opener = mock.Mock() ++ build_opener_mock.return_value = opener ++ response = mock.Mock() ++ response.__enter__ = mock.Mock(return_value=response) ++ response.__exit__ = mock.Mock() ++ response.read.return_value = json.dumps(RESPONSE_DATA_NO_MATCHING_KID) ++ opener.open.return_value = response ++ ++ for _ in range(2): ++ with pytest.raises(PyJWKClientError, match="matches"): ++ jwks_client.get_signing_key(kid) ++ ++ assert opener.open.call_count == 1 ++ ++ def test_unknown_kid_refresh_runs_again_after_cooldown(self) -> None: ++ url = "https://dev-87evx9ru.auth0.com/.well-known/jwks.json" ++ kid = "unknown-kid" ++ jwks_client = PyJWKClient(url, cooldown_duration=0.01) ++ ++ with mock.patch("urllib.request.build_opener") as build_opener_mock: ++ opener = mock.Mock() ++ build_opener_mock.return_value = opener ++ response = mock.Mock() ++ response.__enter__ = mock.Mock(return_value=response) ++ response.__exit__ = mock.Mock() ++ response.read.return_value = json.dumps(RESPONSE_DATA_NO_MATCHING_KID) ++ opener.open.return_value = response ++ ++ clock = [0.0] ++ with mock.patch( ++ "jwt.jwks_client.time.monotonic", side_effect=lambda: clock[0] ++ ): ++ with pytest.raises(PyJWKClientError, match="matches"): ++ jwks_client.get_signing_key(kid) ++ clock[0] = 0.02 ++ with pytest.raises(PyJWKClientError, match="matches"): ++ jwks_client.get_signing_key(kid) ++ ++ assert opener.open.call_count == 2 ++ ++ def test_unknown_kid_refresh_serializes_concurrent_misses(self) -> None: ++ url = "https://dev-87evx9ru.auth0.com/.well-known/jwks.json" ++ kid = "unknown-kid" ++ jwks_client = PyJWKClient(url, cooldown_duration=30) ++ refresh_started = threading.Event() ++ second_done = threading.Event() ++ release_refresh = threading.Event() ++ ++ with mock.patch("urllib.request.build_opener") as build_opener_mock: ++ opener = mock.Mock() ++ build_opener_mock.return_value = opener ++ response = mock.Mock() ++ response.__enter__ = mock.Mock(return_value=response) ++ response.__exit__ = mock.Mock() ++ response.read.return_value = json.dumps(RESPONSE_DATA_NO_MATCHING_KID) ++ ++ opener.open.return_value = response ++ jwks_client.get_jwk_set() ++ jwks_client._last_successful_fetch = 0 ++ ++ def open_response(*args: object, **kwargs: object) -> mock.Mock: ++ if opener.open.call_count == 1: ++ refresh_started.set() ++ release_refresh.wait(timeout=5) ++ return response ++ ++ opener.open.reset_mock() ++ opener.open.side_effect = open_response ++ errors: list[Exception] = [] ++ ++ def lookup() -> None: ++ try: ++ jwks_client.get_signing_key(kid) ++ except PyJWKClientError as error: ++ errors.append(error) ++ ++ first = threading.Thread(target=lookup) ++ ++ def second_lookup() -> None: ++ lookup() ++ second_done.set() ++ ++ second = threading.Thread(target=second_lookup) ++ with mock.patch("jwt.jwks_client.time.monotonic", return_value=31): ++ first.start() ++ assert refresh_started.wait(timeout=5) ++ second.start() ++ assert not second_done.wait(timeout=0.1) ++ release_refresh.set() ++ first.join(timeout=5) ++ second.join(timeout=5) ++ ++ assert len(errors) == 2 ++ assert not first.is_alive() ++ assert not second.is_alive() ++ assert opener.open.call_count == 1 ++ ++ def test_unknown_kid_refresh_ignores_cooldown_when_cache_disabled(self) -> None: ++ url = "https://dev-87evx9ru.auth0.com/.well-known/jwks.json" ++ kid = "unknown-kid" ++ jwks_client = PyJWKClient(url, cache_jwk_set=False, cooldown_duration=30) ++ ++ with mock.patch("urllib.request.build_opener") as build_opener_mock: ++ opener = mock.Mock() ++ build_opener_mock.return_value = opener ++ response = mock.Mock() ++ response.__enter__ = mock.Mock(return_value=response) ++ response.__exit__ = mock.Mock() ++ response.read.side_effect = [ ++ json.dumps(RESPONSE_DATA_NO_MATCHING_KID), ++ json.dumps(RESPONSE_DATA_NO_MATCHING_KID), ++ json.dumps(RESPONSE_DATA_NO_MATCHING_KID), ++ json.dumps(RESPONSE_DATA_NO_MATCHING_KID), ++ ] ++ opener.open.return_value = response ++ ++ for _ in range(2): ++ with pytest.raises(PyJWKClientError, match="matches"): ++ jwks_client.get_signing_key(kid) ++ ++ assert opener.open.call_count == 4 ++ ++ @pytest.mark.parametrize( ++ "cooldown_duration", [float("nan"), float("inf"), float("-inf")] ++ ) ++ def test_unknown_kid_refresh_rejects_non_finite_cooldown( ++ self, cooldown_duration: float ++ ) -> None: ++ url = "https://dev-87evx9ru.auth0.com/.well-known/jwks.json" ++ ++ with pytest.raises(PyJWKClientError, match="Cooldown duration"): ++ PyJWKClient(url, cooldown_duration=cooldown_duration) ++ + def test_get_jwt_set_invalid_lifespan(self) -> None: + url = "https://dev-87evx9ru.auth0.com/.well-known/jwks.json" + +-- +2.35.6 diff --git a/meta-python/recipes-devtools/python/python3-pyjwt_2.12.1.bb b/meta-python/recipes-devtools/python/python3-pyjwt_2.12.1.bb index cd91139d58..25f2451b2f 100644 --- a/meta-python/recipes-devtools/python/python3-pyjwt_2.12.1.bb +++ b/meta-python/recipes-devtools/python/python3-pyjwt_2.12.1.bb @@ -16,6 +16,7 @@ SRC_URI += "file://CVE-2026-48522.patch \ file://CVE-2026-102267.patch \ file://CVE-2026-102268_CVE-2026-102270.patch \ file://CVE-2026-102271.patch \ + file://CVE-2026-101917.patch \ " SRC_URI[sha256sum] = "c74a7a2adf861c04d002db713dd85f84beb242228e671280bf709d765b03672b" From patchwork Fri Oct 16 02:33:21 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Hetvi Thakar -X (hthakar - E INFOCHIPS PRIVATE LIMITED at Cisco)" X-Patchwork-Id: 100922 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id 86DFBCCA46C for ; Fri, 16 Oct 2026 02:33:31 +0000 (UTC) Received: from rcdn-iport-2.cisco.com (rcdn-iport-2.cisco.com [173.37.86.73]) by mx.groups.io with SMTP id smtpd.msgproc02-g2.13504.1792118004184969055 for ; Thu, 15 Oct 2026 19:33:24 -0700 Authentication-Results: mx.groups.io; dkim=fail reason="dkim: message contains an insecure body length tag" header.i=@cisco.com header.s=iport01 header.b=YcNhczwc; spf=pass (domain: cisco.com, ip: 173.37.86.73, mailfrom: hthakar@cisco.com) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=cisco.com; i=@cisco.com; l=4722; q=dns/txt; s=iport01; t=1792118004; x=1793327604; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=ktX+2Dv9aIbmfh8YuRIkTp5jxlPSTfRUJlWbRO+03d8=; b=YcNhczwcX/VwxAW/PsZ91TuuQtVmMB5Bc98d8ohBGFCIcbSI0QvfAlTq UlMO386m79y7JNuNaZNJrvuJyQnAbWCDLTz9xYDVdT6MWa87/RkqlZQ2D qkG/Yi8YkEPFk9wdcolh4HpMfmrgxZmVKcO9kT5EmE6KbkUxqzVkvNev7 f+4JT/E3n4HgCZajlsUwH+u5B9eyR7HJft9AC2ykjXhdu08c9KLxQJFbB 10SBNtXBX6Vv0ceOLTy0CCF8l9u2fFGm8VCqY9U5jw1VS8drQxKG8Q1VX 0+OSoeocnuheaaDfbnpvkk+kjl3tukuLrjIEiXWaeHOMrYk83UMTLCyMi A==; X-CSE-ConnectionGUID: iM/VCInGSTmO5wYpB3ydkg== X-CSE-MsgGUID: Bljn1xmmTwuAJU0kpkFhNg== X-IPAS-Result: A0BIAgDZi9Fq/47/Ja1aHgEBCxIMggULgld1YENJA5ZHA54cgX4PAQEBD0QNBAEBhQUCjhUCJjQJDgECBAMCAwEBAQEBAQEBAQEBAQoBAQUBAQECAQcFgQ4Thk8NkBIBAgEDJwsBGAEtEBwDAQIvKyMIGYMCAYJ0AxG8Z4F5M4EBgykBMQWBHtsyAQsUAQWBM4VAgwOBEYQPXRgBhHwnGxuBcoEVg2mBBYFcAoglBIIigQyBWoFNk3pIgR4DWSwBVRMNCgsHBYFoAzUSKhVuMh2BIz4XgQcbBgWBHYEgghYjGTZ6gQlegSspYAEQF4EJggcCglSCAAIBSUEOB0VTCSVDEkcmIggSCQETGjALgRs4PAkoQRcMcwwdBXIIAg0JBykYDUgRLDcVGQQ+bgeSEx6COC2BDgErF2gSgRsekxqSPaEPCiiDdowilToaM4VbpRQLmH2OCpVfcIRpgWg8gVlwFYMiCUoZD44rDguDYIVkyHYnMgIJAy8BAQcCBw4DC4FokX4BAQ IronPort-Data: A9a23:qdGMWq5ZRVRbdA6hik/0twxRtGnGchMFZxGqfqrLsTDasY5as4F+v jdLWmqDOfmKYGT1f90katzg/EoH6JTUx4IxSlFlqyozZn8b8sCt6fZ1gavT04J+CuWZESqLO u1HMoGowPgcFyGa+1H1dOex9RGQ7InQLpLkEunIJyttcgFtTSYlmHpLlvUw6mJSqYDR7zil5 5Wo/KUzBHf/g2QqazpNtfrawP9SlK2aVA0w7wRWic9j5Dcyp1FNZLoDKKe4KWfPQ4U8NoaSW +bZwbilyXjS9hErB8nNuu6TnpoiG+O60aCm0xK6aoD66vRwjnVaPpUTaJLwXXxqZwChxLid/ jniWauYEm/FNoWU8AgUvoIx/ytWZcWq85efSZSzXFD6I0DuKxPRL/tS4E4ePKhfxM1WB051y fk/dS88djrYlu61z+fuIgVsrpxLwMjDJogTvDRkiDreF/tjGc2FSKTR7tge1zA17ixMNa+BP IxCNnw1MUmGOkEVUrsUIMpWcOOAhmX/ej5RsnqepLE85C7YywkZPL3FbYCMK4HUHJUL9qqej kjC/WKgEhQfCMOC4Bi4qnG0hcHPuyyuDer+E5X9rJaGmma7wXQeDhATX1a3rfS1z0KzRd9bA 0gV4TY1668q+UqmS9PwUxG1rDiDpBF0ZjZLO/cx5AfIzu/f5ByUQzBZCDVAc9ch8sQxQFTGy 2O0oj8gPhQ32JX9dJ5X3u78Qe+aUcTNEVI/WA== IronPort-HdrOrdr: A9a23:/Hh66qHLFFijW/7qpLqEMMeALOsnbusQ8zAXPo5KJiC9Ffbo8P xG88576faZslsssTQb6LK90cq7MBfhHOBOgbX5VI3KNGKNhILrFvAG0WKI+VPd8kPFmtK1/J 0QFZSWcOeAbmRSvILd/BSyFcomzZ2s9aClgvqb8lJWJDsaEp2JK2xCe32m+oocfng/OaYE X-Talos-CUID: 9a23:3hucGm0YWPBP+pQ0cOesLbxfG+ViTFb8yljrH0qfVHlYUJfOWFOT9/Yx X-Talos-MUID: 9a23:qOJ9LwWabZhsoMzq/BXohjc7JMJt37uzIWIwyZYeuOeEEyMlbg== X-IronPort-Anti-Spam-Filtered: true X-IronPort-AV: E=Sophos;i="6.27,161,1787011200"; d="scan'208";a="521956186" Received: from rcdn-l-core-05.cisco.com ([173.37.255.142]) by rcdn-iport-2.cisco.com with ESMTP/TLS/TLS_AES_256_GCM_SHA384; 16 Oct 2026 02:33:23 +0000 Received: from sjc-ads-5245.cisco.com (sjc-ads-5245.cisco.com [10.28.23.9]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by rcdn-l-core-05.cisco.com (Postfix) with ESMTPS id 7D2AA18000223; Fri, 16 Oct 2026 02:33:23 +0000 (GMT) Received: by sjc-ads-5245.cisco.com (Postfix, from userid 1887505) id D4C0ACBEFAB; Thu, 15 Oct 2026 19:33:22 -0700 (PDT) From: "Hetvi Thakar -X (hthakar - E INFOCHIPS PRIVATE LIMITED at Cisco)" To: openembedded-devel@lists.openembedded.org Cc: xe-linux-external@cisco.com Subject: [meta-python][wrynose][PATCH 8/9] python3-pyjwt: fix CVE-2026-102275 Date: Thu, 15 Oct 2026 19:33:21 -0700 Message-Id: <20261016023322.344365-9-hthakar@cisco.com> X-Mailer: git-send-email 2.35.6 In-Reply-To: <20261016023322.344365-1-hthakar@cisco.com> References: <20261016023322.344365-1-hthakar@cisco.com> MIME-Version: 1.0 X-Auto-Response-Suppress: DR, OOF, AutoReply X-Outbound-Client-TLS: ANONYMOUS;sjc-ads-5245.cisco.com [10.28.23.9];TLSv1.3;TLS_AES_256_GCM_SHA384;256 X-Outbound-SMTP-Client: 10.28.23.9, sjc-ads-5245.cisco.com X-Outbound-Node: rcdn-l-core-05.cisco.com List-Id: X-Webhook-Received: from 45-33-107-173.ip.linodeusercontent.com [45.33.107.173] by aws-us-west-2-korg-lkml-1.web.codeaurora.org with HTTPS for ; Fri, 16 Oct 2026 02:33:31 -0000 X-Groupsio-URL: https://lists.openembedded.org/g/openembedded-devel/message/131019 From: Hetvi Thakar This patch applies the upstream fix as referenced in [2], using the commit shown in [1]. [1] https://github.com/jpadilla/pyjwt/commit/3cd9ceec33ced359decbad75b413ad668ae6332c [2] https://github.com/jpadilla/pyjwt/security/advisories/GHSA-x33g-cr3x-6449 Signed-off-by: Hetvi Thakar --- .../python/files/CVE-2026-102275.patch | 82 +++++++++++++++++++ .../python/python3-pyjwt_2.12.1.bb | 1 + 2 files changed, 83 insertions(+) create mode 100644 meta-python/recipes-devtools/python/files/CVE-2026-102275.patch diff --git a/meta-python/recipes-devtools/python/files/CVE-2026-102275.patch b/meta-python/recipes-devtools/python/files/CVE-2026-102275.patch new file mode 100644 index 0000000000..1aab8773d2 --- /dev/null +++ b/meta-python/recipes-devtools/python/files/CVE-2026-102275.patch @@ -0,0 +1,82 @@ +From 3cd9ceec33ced359decbad75b413ad668ae6332c Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jos=C3=A9=20Padilla?= +Date: Fri, 11 Sep 2026 22:29:12 -0400 +Subject: [PATCH] fix: reject inconsistent OKP private keys + +CVE: CVE-2026-102275 +Upstream-Status: Backport [https://github.com/jpadilla/pyjwt/commit/3cd9ceec33ced359decbad75b413ad668ae6332c] + +(cherry picked from commit 3cd9ceec33ced359decbad75b413ad668ae6332c) +Signed-off-by: Hetvi Thakar +--- + jwt/algorithms.py | 14 ++++++++++++-- + tests/test_algorithms.py | 29 +++++++++++++++++++++++++++++ + 2 files changed, 41 insertions(+), 2 deletions(-) + +diff --git a/jwt/algorithms.py b/jwt/algorithms.py +index 432fdcf..03976c9 100644 +--- a/jwt/algorithms.py ++++ b/jwt/algorithms.py +@@ -1036,8 +1036,18 @@ if has_crypto: + return Ed25519PublicKey.from_public_bytes(x) + return Ed448PublicKey.from_public_bytes(x) + d = base64url_decode(obj.get("d")) ++ private_key: Ed25519PrivateKey | Ed448PrivateKey + if curve == "Ed25519": +- return Ed25519PrivateKey.from_private_bytes(d) +- return Ed448PrivateKey.from_private_bytes(d) ++ private_key = Ed25519PrivateKey.from_private_bytes(d) ++ else: ++ private_key = Ed448PrivateKey.from_private_bytes(d) ++ if ( ++ private_key.public_key().public_bytes( ++ encoding=Encoding.Raw, format=PublicFormat.Raw ++ ) ++ != x ++ ): ++ raise InvalidKeyError("Public key does not match private key") ++ return private_key + except ValueError as err: + raise InvalidKeyError("Invalid key parameter") from err +diff --git a/tests/test_algorithms.py b/tests/test_algorithms.py +index acaa1fe..089b881 100644 +--- a/tests/test_algorithms.py ++++ b/tests/test_algorithms.py +@@ -933,6 +933,35 @@ class TestAlgorithmsRFC7520: + + @crypto_required + class TestOKPAlgorithms: ++ @pytest.mark.parametrize("curve", ("Ed25519", "Ed448")) ++ @pytest.mark.parametrize("as_dict", (False, True)) ++ def test_okp_jwk_should_reject_inconsistent_private_key( ++ self, curve: str, as_dict: bool ++ ) -> None: ++ with open(key_path(f"jwk_okp_key_{curve}.json")) as keyfile: ++ jwk = json.load(keyfile) ++ ++ d = base64url_decode(jwk["d"]) ++ jwk["d"] = ( ++ base64.urlsafe_b64encode(bytes([d[0] ^ 1]) + d[1:]).rstrip(b"=").decode() ++ ) ++ ++ with pytest.raises(InvalidKeyError): ++ OKPAlgorithm.from_jwk(jwk if as_dict else json.dumps(jwk)) ++ ++ @pytest.mark.parametrize("curve", ("Ed25519", "Ed448")) ++ @pytest.mark.parametrize("length", (0, 1, 56, 58)) ++ def test_okp_jwk_should_reject_private_key_with_invalid_public_length( ++ self, curve: str, length: int ++ ) -> None: ++ with open(key_path(f"jwk_okp_key_{curve}.json")) as keyfile: ++ jwk = json.load(keyfile) ++ ++ jwk["x"] = base64.urlsafe_b64encode(b"\x00" * length).rstrip(b"=").decode() ++ ++ with pytest.raises(InvalidKeyError): ++ OKPAlgorithm.from_jwk(jwk) ++ + hello_world_sig = b"Qxa47mk/azzUgmY2StAOguAd4P7YBLpyCfU3JdbaiWnXM4o4WibXwmIHvNYgN3frtE2fcyd8OYEaOiD/KiwkCg==" + hello_world_sig_pem = b"9ueQE7PT8uudHIQb2zZZ7tB7k1X3jeTnIfOVvGCINZejrqQbru1EXPeuMlGcQEZrGkLVcfMmr99W/+byxfppAg==" + hello_world = b"Hello World!" +-- +2.35.6 diff --git a/meta-python/recipes-devtools/python/python3-pyjwt_2.12.1.bb b/meta-python/recipes-devtools/python/python3-pyjwt_2.12.1.bb index 25f2451b2f..8953a781de 100644 --- a/meta-python/recipes-devtools/python/python3-pyjwt_2.12.1.bb +++ b/meta-python/recipes-devtools/python/python3-pyjwt_2.12.1.bb @@ -17,6 +17,7 @@ SRC_URI += "file://CVE-2026-48522.patch \ file://CVE-2026-102268_CVE-2026-102270.patch \ file://CVE-2026-102271.patch \ file://CVE-2026-101917.patch \ + file://CVE-2026-102275.patch \ " SRC_URI[sha256sum] = "c74a7a2adf861c04d002db713dd85f84beb242228e671280bf709d765b03672b" From patchwork Fri Oct 16 02:33:22 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Hetvi Thakar -X (hthakar - E INFOCHIPS PRIVATE LIMITED at Cisco)" X-Patchwork-Id: 100920 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id 4991FCCA463 for ; Fri, 16 Oct 2026 02:33:31 +0000 (UTC) Received: from rcdn-iport-5.cisco.com (rcdn-iport-5.cisco.com [173.37.86.76]) by mx.groups.io with SMTP id smtpd.msgproc02-g2.13506.1792118004428734226 for ; Thu, 15 Oct 2026 19:33:24 -0700 Authentication-Results: mx.groups.io; dkim=fail reason="dkim: message contains an insecure body length tag" header.i=@cisco.com header.s=iport01 header.b=foQ+c5Ds; spf=pass (domain: cisco.com, ip: 173.37.86.76, mailfrom: hthakar@cisco.com) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=cisco.com; i=@cisco.com; l=5715; q=dns/txt; s=iport01; t=1792118004; x=1793327604; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=HB3YktQLOxTfKi67Q+gHo9759IMt1ZbQ+EsvFLFHlsg=; b=foQ+c5DsMktIQsAkPl8vGEJ4/jUPjIfCboR6aJ4JJ5pfoVA5f0rEKX0z KVmZCMU8UmpuXqYvJqzdp9+YbKi8fNi4aM1UhzrOwE9mRqDOnY/0B+73g HClIdUhYyAU/OzxQj3y8AcnX6lsPH5+zAWh6j8l96w0miR8pPT1Kb20Vx BmJV2r26RAtLgcENZY/UXdkX8dN1JJiiNJrJW9DVURRuGULejf/AolMf0 QalUYMNbXJKS5ZTQrV1MsVJMErS8gAS0tLePRD2CJ+SKd+vXHSdLLeplJ 0CY2ZTvsQOJAwXD7eQp9KtmGz22oGr9L80HvP/+f7qQEc2n+kf9IwSjze A==; X-CSE-ConnectionGUID: dexvJcafQVitsACHpYLN7Q== X-CSE-MsgGUID: m6SLEXZ3SwG8HLQZgumDMA== X-IPAS-Result: A0BJAgBdi9Fq/5H/Ja1aEwEBgkSCV3VgQ0kDlkcDnhyBfg8BAQEPRA0EAQGFBQKOFQImNAkOAQIEAwIDAQEBAQEBAQEBAQEBCgEBBQEBAQIBBwWBDhOGTw2QEgECAQMnCwEYAS0QHAMBAi8rIwgZgwIBgnQDEQa8XIF5M4EBgykBgVTbMgELFAEFgTOFQIgjXRgBhHwnGxuBcoEVg2mBBYFcAoglBIIigQyBWpVHSIEeA1ksAVUTDQoLBwWBaAM1EioVbjIdgSM+F4EHGwYFgR2BIIIWIxk2eoEJXoErKWABEBeBCYIHAoJUggACAUlBDgdFUwklQxJHJiIIEgkBExowC4EbODwJKEEXDHMMHQVyCAINCQcpGA1IESw3FRkEPm4HkhMegmWBDgErF2iBLR6lV6EPCiiDdowilToaM6pvC5h9jgqBTZUChGmBaDyBWXAVgyIJShkPji4LC4NgzlonMgIJAy8BAQcCBw4DC4FokX4BAQ IronPort-Data: A9a23:2eDlt6x97OVDuPjf0396t+dmxyrEfRIJ4+MujC+fZmUNrF6WrkUPz 2QfW2mBaamJYWv2KIpwaIy1900P7J7Rm9Q2Sgs/+VhgHilAwSbn6Xt1DatR0we6dJCroJdPt p1GAjX4BJlqCCKa/lHyYuCJQUBUjcmgXqD7BPPPJhd/TAplTDZJoR94kobVuKYw6TSCK13L4 4yaT/H3Ygf/hWcsazxMsspvlTs21BjMkGJA1rABTagjUG/2zxE9EJ8ZLKetGHr0KqE8NvK6X evK0Iai9Wrf+Ro3Yvv9+losWhRXKlJ6FVHmZkt+A8BOsDAbzsAB+vpT2M4nVKtio27hc+adZ zl6ncfYpQ8BZsUgkQmGOvVSO3kW0aZuoNcrLZUj2CCe5xWuTpfi/xlhJE07LZM68e95OF9P6 ecxAxAVXzSl2NvjldpXSsE07igiBNPgMIVavjRryivUSK52B5vCWK7No9Rf2V/chOgXQq2YP JVfM2cyKk2cPnWjOX9PYH46tOe0hnD8eidwo1OOrq1x6G/WpOB0+OW2boaPIIXUHa25mG6d+ Fni0lTLWSoFG4y/7QO3/W+pqsrmyHaTtIU6UefQGuRRqFqLy2oeDRcbWVe2rby1h1CzX/pbK lcI4WwptaU0+UmhQ9XxUhH+p2SL1iPwQPJKGOE8rQXIwa3O7kPBVi4PTyVKb5ots8peqSEW6 2JlVujBXVRH2IB5g1rHnltIhVte4RQoEFI= IronPort-HdrOrdr: A9a23:fEzTvK5SsstyPeO8OAPXwBDXdLJyesId70hD6qm+c3Nom6uj5q eTdZsgtCMc5Ax9ZJhko6HjBEDiewK5yXcK2+ks1N6ZNWGM0ldAbrsSiLcKqAePJ8SRzIJgPI 5bAs5D4aXLfDtHpPe/xhWkGNA9x9TC2qWpieDCi0pJd2hRGthdB8MTMHfhLqWwLzM2faYEKA == X-Talos-CUID: 9a23:zg2ZomCzcEC63av6EyVq5FA2EckrS0Pc0Gz5CG+gOEJPF4TAHA== X-Talos-MUID: 9a23:sVPzmAuV3wZZIcZlKc2ngW9ZEOpY0f+VF29dsbE/icaZMABVEmLI X-IronPort-Anti-Spam-Filtered: true X-IronPort-AV: E=Sophos;i="6.27,161,1787011200"; d="scan'208";a="536422160" Received: from rcdn-l-core-08.cisco.com ([173.37.255.145]) by rcdn-iport-5.cisco.com with ESMTP/TLS/TLS_AES_256_GCM_SHA384; 16 Oct 2026 02:33:23 +0000 Received: from sjc-ads-5245.cisco.com (sjc-ads-5245.cisco.com [10.28.23.9]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by rcdn-l-core-08.cisco.com (Postfix) with ESMTPS id 7EAE218000469; Fri, 16 Oct 2026 02:33:23 +0000 (GMT) Received: by sjc-ads-5245.cisco.com (Postfix, from userid 1887505) id DB470CBEFBF; Thu, 15 Oct 2026 19:33:22 -0700 (PDT) From: "Hetvi Thakar -X (hthakar - E INFOCHIPS PRIVATE LIMITED at Cisco)" To: openembedded-devel@lists.openembedded.org Cc: xe-linux-external@cisco.com Subject: [meta-python][wrynose][PATCH 9/9] python3-pyjwt: fix CVE-2026-101918 Date: Thu, 15 Oct 2026 19:33:22 -0700 Message-Id: <20261016023322.344365-10-hthakar@cisco.com> X-Mailer: git-send-email 2.35.6 In-Reply-To: <20261016023322.344365-1-hthakar@cisco.com> References: <20261016023322.344365-1-hthakar@cisco.com> MIME-Version: 1.0 X-Auto-Response-Suppress: DR, OOF, AutoReply X-Outbound-Client-TLS: ANONYMOUS;sjc-ads-5245.cisco.com [10.28.23.9];TLSv1.3;TLS_AES_256_GCM_SHA384;256 X-Outbound-SMTP-Client: 10.28.23.9, sjc-ads-5245.cisco.com X-Outbound-Node: rcdn-l-core-08.cisco.com List-Id: X-Webhook-Received: from 45-33-107-173.ip.linodeusercontent.com [45.33.107.173] by aws-us-west-2-korg-lkml-1.web.codeaurora.org with HTTPS for ; Fri, 16 Oct 2026 02:33:31 -0000 X-Groupsio-URL: https://lists.openembedded.org/g/openembedded-devel/message/131020 From: Hetvi Thakar This patch applies the upstream fix as referenced in [2], using the commit shown in [1]. [1] https://github.com/jpadilla/pyjwt/commit/5fde08a6cf906aa7698de2d6391d88b73006b17b [2] https://github.com/jpadilla/pyjwt/security/advisories/GHSA-42vr-xj54-vc7v Signed-off-by: Hetvi Thakar --- .../python/files/CVE-2026-101918.patch | 122 ++++++++++++++++++ .../python/python3-pyjwt_2.12.1.bb | 1 + 2 files changed, 123 insertions(+) create mode 100644 meta-python/recipes-devtools/python/files/CVE-2026-101918.patch diff --git a/meta-python/recipes-devtools/python/files/CVE-2026-101918.patch b/meta-python/recipes-devtools/python/files/CVE-2026-101918.patch new file mode 100644 index 0000000000..4041a554ff --- /dev/null +++ b/meta-python/recipes-devtools/python/files/CVE-2026-101918.patch @@ -0,0 +1,122 @@ +From 5fde08a6cf906aa7698de2d6391d88b73006b17b Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jos=C3=A9=20Padilla?= +Date: Tue, 22 Sep 2026 11:44:19 -0400 +Subject: [PATCH] fix: normalize recursive JWT payload errors + +CVE: CVE-2026-101918 +Upstream-Status: Backport [https://github.com/jpadilla/pyjwt/commit/5fde08a6cf906aa7698de2d6391d88b73006b17b] + +Backport Changes: +- Adapted the PyJWKClient regression-test imports to the older Wrynose + test module, which lacks later unrelated PyJWKSet imports. + +(cherry picked from commit 5fde08a6cf906aa7698de2d6391d88b73006b17b) +Signed-off-by: Hetvi Thakar +--- + jwt/api_jwt.py | 2 +- + tests/test_api_jwt.py | 18 +++++++++++++++++- + tests/test_jwks_client.py | 26 +++++++++++++++++++++++++- + 3 files changed, 43 insertions(+), 3 deletions(-) + +diff --git a/jwt/api_jwt.py b/jwt/api_jwt.py +index f298ea9..d6917c0 100644 +--- a/jwt/api_jwt.py ++++ b/jwt/api_jwt.py +@@ -293,7 +293,7 @@ class PyJWT: + """ + try: + payload: dict[str, Any] = json.loads(decoded["payload"]) +- except ValueError as e: ++ except (ValueError, RecursionError) as e: + raise DecodeError(f"Invalid payload string: {e}") from e + if not isinstance(payload, dict): + raise DecodeError("Invalid payload string: must be a json object") +diff --git a/tests/test_api_jwt.py b/tests/test_api_jwt.py +index dd28816..96f9179 100644 +--- a/tests/test_api_jwt.py ++++ b/tests/test_api_jwt.py +@@ -7,6 +7,7 @@ from decimal import Decimal + + import pytest + ++import jwt as pyjwt + from jwt.types import Options + from jwt.api_jwk import PyJWK + from jwt.api_jwt import PyJWT +@@ -21,7 +22,7 @@ from jwt.exceptions import ( + InvalidSubjectError, + MissingRequiredClaimError, + ) +-from jwt.utils import base64url_decode ++from jwt.utils import base64url_decode, base64url_encode + from jwt.warnings import RemovedInPyjwt3Warning + + from .utils import crypto_required, key_path, utc_timestamp +@@ -177,6 +178,21 @@ class TestJWT: + + assert "Invalid payload string" in str(exc.value) + ++ def test_decode_deeply_nested_payload_throws_decode_error(self) -> None: ++ nested_payload = b"[" * 100_000 + b"]" * 100_000 ++ token = ".".join( ++ ( ++ "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9", ++ base64url_encode(nested_payload).decode(), ++ "", ++ ) ++ ) ++ ++ with pytest.raises(DecodeError, match="Invalid payload") as exc: ++ pyjwt.decode(token, options={"verify_signature": False}) ++ ++ assert isinstance(exc.value.__cause__, RecursionError) ++ + def test_decode_with_non_mapping_payload_throws_exception(self, jwt: PyJWT) -> None: + secret = "secret" + example_jwt = ( +diff --git a/tests/test_jwks_client.py b/tests/test_jwks_client.py +index c66dfd7..cf6f6e1 100644 +--- a/tests/test_jwks_client.py ++++ b/tests/test_jwks_client.py +@@ -16,7 +16,12 @@ import jwt + from jwt import PyJWKClient + from jwt.jwks_client import _NoRedirectHandler + from jwt.api_jwk import PyJWK +-from jwt.exceptions import PyJWKClientConnectionError, PyJWKClientError ++from jwt.exceptions import ( ++ DecodeError, ++ PyJWKClientConnectionError, ++ PyJWKClientError, ++) ++from jwt.utils import base64url_encode + + from .utils import crypto_required + +@@ -298,6 +303,25 @@ class TestPyJWKClient: + "gty": "client-credentials", + } + ++ def test_get_signing_key_from_jwt_rejects_deeply_nested_payload(self) -> None: ++ nested_payload = b"[" * 100_000 + b"]" * 100_000 ++ header = b'{"alg":"RS256","kid":"test-key"}' ++ token = ".".join( ++ ( ++ base64url_encode(header).decode(), ++ base64url_encode(nested_payload).decode(), ++ "", ++ ) ++ ) ++ ++ with mocked_success_response(RESPONSE_DATA_WITH_MATCHING_KID) as open_mock: ++ jwks_client = PyJWKClient("https://example.test/.well-known/jwks.json") ++ with pytest.raises(DecodeError, match="Invalid payload") as exc: ++ jwks_client.get_signing_key_from_jwt(token) ++ ++ assert isinstance(exc.value.__cause__, RecursionError) ++ assert open_mock.call_count == 0 ++ + def test_get_jwk_set_caches_result(self) -> None: + url = "https://dev-87evx9ru.auth0.com/.well-known/jwks.json" + +-- +2.35.6 diff --git a/meta-python/recipes-devtools/python/python3-pyjwt_2.12.1.bb b/meta-python/recipes-devtools/python/python3-pyjwt_2.12.1.bb index 8953a781de..8b3ea9da1c 100644 --- a/meta-python/recipes-devtools/python/python3-pyjwt_2.12.1.bb +++ b/meta-python/recipes-devtools/python/python3-pyjwt_2.12.1.bb @@ -18,6 +18,7 @@ SRC_URI += "file://CVE-2026-48522.patch \ file://CVE-2026-102271.patch \ file://CVE-2026-101917.patch \ file://CVE-2026-102275.patch \ + file://CVE-2026-101918.patch \ " SRC_URI[sha256sum] = "c74a7a2adf861c04d002db713dd85f84beb242228e671280bf709d765b03672b"