From patchwork Thu Aug 6 05:50:57 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: 94659 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 14798C55ABF for ; Thu, 6 Aug 2026 05:51:24 +0000 (UTC) Received: from alln-iport-2.cisco.com (alln-iport-2.cisco.com [173.37.142.89]) by mx.groups.io with SMTP id smtpd.msgproc01-g2.13105.1785995477785717389 for ; Wed, 05 Aug 2026 22:51:18 -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=N2H9PNuk; spf=pass (domain: cisco.com, ip: 173.37.142.89, mailfrom: hthakar@cisco.com) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=cisco.com; i=@cisco.com; l=5490; q=dns/txt; s=iport01; t=1785995477; x=1787205077; h=from:to:cc:subject:date:message-id:mime-version: content-transfer-encoding; bh=5z6tR9qRkwQaUnWmg6pMD6S7vldh+ew4GpQ7949f42M=; b=N2H9PNukDq8InYPsWShs+PwjEL8gq9IJFbbjNcx/xPQeSnMcDOxoMrbK YrHB6DIc11RbIIXLfKTgXB1GS2G6kNsO71r42Mp2UBwHSy/dwjPr63qSQ TaNiXd9zaQmvSK4h0FDdbbPkjlmmvTmUunU2X+Ta8yF6UdPs/lYudJ8F2 7TALwsR9ZmFYiSnZAZQ1xbciomwysvU8UonKk+WL6SOnIBGYHwpdKhPlr mbZmzK/A0NJDBZWZz9d+/S6F2RNTckHnUlOgRwgzINarL0wwPl1YjkEzM sMl0TgBJMVutYPNIKlVZrn00+wBTUJ7F+t9FGhM8edvARfLhXNqJOxYMb g==; X-CSE-ConnectionGUID: wKkydNEqRtSVOLiJwHLbOg== X-CSE-MsgGUID: qzBKm/UdSGy/AOVUwN2wHg== X-IPAS-Result: A0BHAgA8IHRq/5EQJK1aEwEBgkSCV3ReQ0mVXmyeHoF+DwEBAQ9EDQQBAYUFjWgCJjQJDgECBAMCAwEBAQEBAQEBAQEBCwEBBQEBAQIBBwWBDhOGTw2GWgECASoLARgBGxIsAwECWiMhgwIBgnQDEQa8bIF5M4EBgygBgVTbLgELFAEFgTOFP4ghXRgBhHwnGxuBcoEVg2mBBYFRCwKBJ4Z+BIIigQyBWoFLj0tIgR4DWSwBVRMNCgsHBYFmAzUSKhVuMh2BIz4XgQ0bBwWBHYEohGgjGTZ6gQlegS0qZAESF4EJgm8CgnqBKQsYDUgRLDcUGQQ+bgeNfyCBTmESexMBKgEXaIFLkzSSJKEPCiiDdYwhlToaM4QEgVeSQJJRC5h9jgqBTZQ0T4RpgWg8gVlwFTuCZwlKGQ+OLgoLg2CFE8cmJzICCTIBAQcCBw4DC4FokAACJgeBTwEB IronPort-Data: A9a23:Lif35ajYfaJqBmS6xhN13ZH/X161NhEKZh0ujC45NGQN5FlHY01je htvDz+EaKuMYzf1Ktggb9/gpEhV75HVyYJiG1BsqX09QihjpJueD7x1DKtf0wB+jyHnZBg6h ynLQoCYdKjYdleF+FH1dOOn9SUgvU2xbuKUIPbePSxsThNTRi4kiBZy88Y0mYcAbeKRW2thg vus5ZeCULOZ82QsaDxMu/re8EkHUMna4Vv0gHRvPZing3eG/5UlJMp3Db28KXL+Xr5VEoaSL 87fzKu093/u5BwkDNWoiN7TKiXmlZaLYGBiIlIPM0STqkAqSh4ai87XB9JAAatjsAhlqvgqo Dl7WTNcfi9yVkHEsLx1vxC1iEiSN4UekFPMCSDXXcB+UyQqflO0q8iCAn3aMqUH2eVmDUdj7 MYEEw4qShGhmMKSypW0H7wEasQLdKEHPasWvnVmiDWcBvE8TNWbE+PB5MRT23E7gcUm8fT2P pVCL2ExKk2eJUQTZz/7C7pm9AusrnnjczRboUi9rqss6G+Vxwt0uFToGIWEJIfQGJQExy50o Erf7U7aB1YnOOew2H2s1UyRmcmVggP0Ddd6+LqQs6QCbEeo7msLBRsbUFG2rfW0hguyVsxSL 2QQ+zEytu417EGtQ9z3UhG0rXLCuQQTM+e8CMUz7AWLj66R6AGDCy1cHnhKaccts4k9QjlCO kK1ou4FzAdH6NW9IU9xPJ/Oxd9uEUD59VM/WBI= IronPort-HdrOrdr: A9a23:yy0i+an/yFPTmn/3OEQYJNzjHcjpDfIA3DAbv31ZSRFFG/FwWf rAoB19726QtN9/YhAdcLy7VZVoIkmsl6Kdn7NwAV7KZmCP0wGVxepZg7cKrQeNJ8TWzJ846U 4ZSdkcNPTASX5nkM39/A60V/wkwNWB7eSUoN229QYLcemvAJsQljuQzW2gYytLeDU= X-Talos-CUID: 9a23:qu2KYmMpMdWClO5DRwpk5UIyN9kfbkbj61PRAVCYLWxOR+jA X-Talos-MUID: 9a23:Ag14Ng6dYoqQ91xBmXhrNDy6xoxx8Y6NDQcwna4pqo6tEhJNJBHHkxS4F9o= X-IronPort-Anti-Spam-Filtered: true X-IronPort-AV: E=Sophos;i="6.25,207,1779148800"; d="scan'208";a="796325991" Received: from alln-l-core-08.cisco.com ([173.36.16.145]) by alln-iport-2.cisco.com with ESMTP/TLS/TLS_AES_256_GCM_SHA384; 06 Aug 2026 05:51:16 +0000 Received: from sjc-ads-5471.cisco.com (sjc-ads-5471.cisco.com [10.28.23.235]) (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 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "ciscoit-managed-infra-smtp-auth.cisco.com", Issuer "Internal Private TLS SubCA" (verified OK)) by alln-l-core-08.cisco.com (Postfix) with ESMTPS id BBDDF18000440; Thu, 6 Aug 2026 05:51:16 +0000 (GMT) Received: by sjc-ads-5471.cisco.com (Postfix, from userid 1887505) id 5FF9BCC12A6; Wed, 5 Aug 2026 22:51:16 -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, Hetvi Thakar Subject: [meta-python][scarthgap][PATCH 1/5] python3-pyjwt: Fix CVE-2026-48522 Date: Wed, 5 Aug 2026 22:50:57 -0700 Message-Id: <20260806055101.23160-1-hthakar@cisco.com> X-Mailer: git-send-email 2.35.6 MIME-Version: 1.0 X-Auto-Response-Suppress: DR, OOF, AutoReply X-Outbound-Client-TLS: VERIFIED;sjc-ads-5471.cisco.com [10.28.23.235];TLSv1.3;TLS_AES_256_GCM_SHA384;256;ciscoit-managed-infra-smtp-auth.cisco.com X-Outbound-SMTP-Client: 10.28.23.235, sjc-ads-5471.cisco.com X-Outbound-Node: alln-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 ; Thu, 06 Aug 2026 05:51:24 -0000 X-Groupsio-URL: https://lists.openembedded.org/g/openembedded-devel/message/128832 From: Hetvi Thakar Restrict PyJWKClient JWKS retrieval to HTTP and HTTPS. urllib otherwise accepts schemes such as file, FTP and data, allowing attacker-influenced URLs to reach unintended resources. This patch applies the relevant subset of the upstream 2.13.0 fix. The upstream commit is referenced in [1], and the public advisory is referenced in [2]. [1] https://github.com/jpadilla/pyjwt/commit/95791b1759b8aa4f2203575d344d5c78564cdc81 [2] https://github.com/advisories/GHSA-993g-76c3-p5m4 Signed-off-by: Hetvi Thakar --- .../python/python3-pyjwt/CVE-2026-48522.patch | 94 +++++++++++++++++++ .../python/python3-pyjwt_2.8.0.bb | 5 +- 2 files changed, 98 insertions(+), 1 deletion(-) create mode 100644 meta-python/recipes-devtools/python/python3-pyjwt/CVE-2026-48522.patch diff --git a/meta-python/recipes-devtools/python/python3-pyjwt/CVE-2026-48522.patch b/meta-python/recipes-devtools/python/python3-pyjwt/CVE-2026-48522.patch new file mode 100644 index 0000000000..fbf17d7cc1 --- /dev/null +++ b/meta-python/recipes-devtools/python/python3-pyjwt/CVE-2026-48522.patch @@ -0,0 +1,94 @@ +From ff542029d6865add176b3d4b650d8f1dc514ac85 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jos=C3=A9=20Padilla?= +Date: Mon, 3 Aug 2026 03:20:44 -0700 +Subject: [PATCH] PyJWKClient: reject non-HTTP(S) JWKS URIs + +Restrict JWKS retrieval to HTTP and HTTPS. urllib otherwise accepts +additional schemes such as file, FTP and data, allowing +attacker-influenced URLs to reach unintended resources. + +CVE: CVE-2026-48522 +Upstream-Status: Backport [https://github.com/jpadilla/pyjwt/commit/95791b1759b8aa4f2203575d344d5c78564cdc81] + +Backport Changes: +- Extracted only the CVE-2026-48522 URI-scheme validation and regression + tests from the bundled upstream 2.13.0 commit. The other requested CVE + fixes are carried as separate patches. +- Adapted the hunk context to the PyJWT 2.8.0 constructor and typing imports. +- Omitted upstream test comments while retaining the same URI cases and + assertions. +- Omitted the 2.13.0 version and changelog updates, CVE-2026-48523 (which + does not affect 2.8.0), and unrelated hardening from the bundled commit. + +(cherry picked from commit 95791b1759b8aa4f2203575d344d5c78564cdc81) +Signed-off-by: Hetvi Thakar +--- + jwt/jwks_client.py | 11 +++++++++++ + tests/test_jwks_client.py | 25 +++++++++++++++++++++++++ + 2 files changed, 36 insertions(+) + +diff --git a/jwt/jwks_client.py b/jwt/jwks_client.py +index f19b10a..18de342 100644 +--- a/jwt/jwks_client.py ++++ b/jwt/jwks_client.py +@@ -4,6 +4,7 @@ from functools import lru_cache + from ssl import SSLContext + from typing import Any, Dict, List, Optional + from urllib.error import URLError ++from urllib.parse import urlparse + + from .api_jwk import PyJWK, PyJWKSet + from .api_jwt import decode_complete as decode_token +@@ -25,6 +26,16 @@ class PyJWKClient: + ): + if headers is None: + headers = {} ++ # urllib's default OpenerDirector also handles file://, ftp://, and ++ # data: URIs. Reject anything that isn't http(s) eagerly so a caller ++ # passing an attacker-influenced URL (e.g. taken from a `jku` token ++ # header) can't read local files or reach other unintended schemes. ++ scheme = urlparse(uri).scheme.lower() ++ if scheme not in ("http", "https"): ++ raise PyJWKClientError( ++ f"Invalid JWKS URI scheme {scheme!r}: only 'http' and 'https' " ++ f"are supported." ++ ) + self.uri = uri + self.jwk_set_cache: Optional[JWKSetCache] = None + self.headers = headers +diff --git a/tests/test_jwks_client.py b/tests/test_jwks_client.py +index c3951ea..d4bdd35 100644 +--- a/tests/test_jwks_client.py ++++ b/tests/test_jwks_client.py +@@ -327,6 +327,31 @@ class TestPyJWKClient: + jwks_client = PyJWKClient(url, lifespan=-1) + assert jwks_client is None + ++ @pytest.mark.parametrize( ++ "uri", ++ [ ++ "file:///etc/passwd", ++ "ftp://example.org/keys.json", ++ 'data:application/json,{"keys":[]}', ++ "/etc/passwd", ++ "ldap://internal.test/jwks", ++ ], ++ ) ++ def test_pyjwkclient_rejects_non_http_schemes(self, uri: str) -> None: ++ with pytest.raises(PyJWKClientError, match="Invalid JWKS URI scheme"): ++ PyJWKClient(uri) ++ ++ @pytest.mark.parametrize( ++ "uri", ++ [ ++ "http://localhost/jwks.json", ++ "https://example.test/jwks.json", ++ "HTTPS://Example.Test/jwks.json", ++ ], ++ ) ++ def test_pyjwkclient_accepts_http_https_schemes(self, uri: str) -> None: ++ PyJWKClient(uri) ++ + def test_get_jwt_set_timeout(self): + url = "https://dev-87evx9ru.auth0.com/.well-known/jwks.json" + jwks_client = PyJWKClient(url, timeout=5) diff --git a/meta-python/recipes-devtools/python/python3-pyjwt_2.8.0.bb b/meta-python/recipes-devtools/python/python3-pyjwt_2.8.0.bb index 9753559171..55884cddad 100644 --- a/meta-python/recipes-devtools/python/python3-pyjwt_2.8.0.bb +++ b/meta-python/recipes-devtools/python/python3-pyjwt_2.8.0.bb @@ -5,7 +5,10 @@ HOMEPAGE = "http://github.com/jpadilla/pyjwt" LICENSE = "MIT" LIC_FILES_CHKSUM = "file://LICENSE;md5=e4b56d2c9973d8cf54655555be06e551" -SRC_URI += "file://CVE-2026-32597.patch" +SRC_URI += " \ + file://CVE-2026-32597.patch \ + file://CVE-2026-48522.patch \ +" SRC_URI[sha256sum] = "57e28d156e3d5c10088e0c68abb90bfac3df82b40a71bd0daa20c65ccd5c23de" PYPI_PACKAGE = "PyJWT" From patchwork Thu Aug 6 05:50:58 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: 94661 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 E9058C56205 for ; Thu, 6 Aug 2026 05:51:33 +0000 (UTC) Received: from alln-iport-4.cisco.com (alln-iport-4.cisco.com [173.37.142.91]) by mx.groups.io with SMTP id smtpd.msgproc02-g2.13570.1785995483792386520 for ; Wed, 05 Aug 2026 22:51: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=J+79oaAB; spf=pass (domain: cisco.com, ip: 173.37.142.91, mailfrom: hthakar@cisco.com) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=cisco.com; i=@cisco.com; l=6080; q=dns/txt; s=iport01; t=1785995483; x=1787205083; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=AX/kCCdUpt6CUVQU001ZLy1CMrygQ5TCX6KwTlnC3WU=; b=J+79oaABCwqigukTpoIA+antf+F2mBZGfaw2IxWpHwPEmgQgPb4gUvMu hNUmw9Jx5esOq11GoTJABxG+x6TDc11Ym52Rjezz3aV4gvOMl4ZVxLlxY Q/CL5+OZnA1R8B4L4ydF82FCPWX5J0aTM7X9KB8dxz8Ek9esvvR6fAe98 PWaHbYB3f6+BR9MCuBEpwt979oijfkQ9DXpaEnS7kbxnjMcaqeBKvJiSi 6ByZvTlUALRVtvPt+U3CcvOCT4Yz6e22BvuBVEVRxSi8LBrUGq1XoUc4E sm3gV/WqDW5z60YJcOTbIaUJNpMPKV8IjjF6O5j/K1Ch+DeHUJAyNj8Qk Q==; X-CSE-ConnectionGUID: ggn5gfX5Qtu1wkpDdtjqGQ== X-CSE-MsgGUID: 9Or5jJn2SUy58ErxxPUHxQ== X-IPAS-Result: A0BLAgC3H3Rq/5UQJK1aEwEBgkSCV3ReQ0mVXmwDkUqMUYF+DwEBAQ9EDQQBAYUFAo1mAiY0CQ4BAgQDAgMBAQEBAQEBAQEBAQsBAQUBAQECAQcFgQ4Thk8NhloBAgEDJwsBFAQBGxIQHAMBAi8rIwgZgwIBgnQDEQa8a4F5M4EBgk9ZAYFU2y4BCxQBBYEzgWGDXoghXRgBhHwnGxuBcoEVg2mBBYFcAoglBIIiehKBWpEWSIEeA1ksAVUTDQoLBwWBZgM1EioVbjIdgSM+F4ENGwcFgR2BKIRoIxk2eoEJXoEtKmQBEheBCYJvAoJ6gSkLGA1IESw3FBkEPm4HjX8ggiEgewkKASsEe4FLBJMMkkiBNZ9aCiiDdYwhlToaM4QEpmgLmH2CWYsxgU2TaUoBT4RpgWg8gVlwFYMiCUoZD44uCguDYMw5JzICCTIBAQcCBw4DC4FokX4BAQ IronPort-Data: A9a23:tSBP3aAZ7Sa6mhVW/3/iw5YqxClBgxIJ4kV8jS/XYbTApGsg1T0Ey TBNW2GDaPiCYmv9KtElPoy08RsCuJfSzdYwOVdlrnsFo1CmBibm6XV1Cm+qYkt+++WaFBoPA /02M4eGdIZvCCeA+n9BC5C5xVFkz6aEW7HgP+DNPyF1VGdMRTwo4f5Zs7ZRbrVA357jXmthh fuo+5eBYA/9hmYuWo4pw/vrRC1H7ayaVAww5jTSVdgT1HfCmn8cCo4oJK3ZBxPQXolOE+emc P3Ixbe/83mx109F5gSNy+uTnuUiG9Y+DCDW4pZkc/HKbitq+kTe5p0G2M80Mi+7vdkmc+dZk 72hvbToIesg0zaldO41C3G0GAkmVUFKFSOuzXWX6aSuI0P6n3TEzPpoUU44DdAh5vsuHmJW2 fAEKikiV0XW7w626OrTpuhEj8AnKozveYgYoHwllGufBvc9SpeFSKLPjTNa9G5v3YYVQ7CHO YxANWsHgBfoO3WjPn8XFJI3n+6yrnL+aDZf7lmSoMLb5kCMnV0oj+K8aIe9ltqiFOJPw0S6o Dj9wnWkUjwAJMyn9BqVyyf57gPItWahMG4IL5W/7vNsjViZy2AfBRFTWValrP2Rjk+lR8kZL FQZ/Ccrp6U++EGnCN7nUHWFTGWstxoYXZ9UVuY98gzIk/CS6AeCDW9CRTlEADA7iPILqfUR/ gfht7vU6fZH6tV5lVr1Gm+okA6P IronPort-HdrOrdr: A9a23:GY5XXapsElnF3UakkyuynBEaV5rzeYIsimQD101hICG9vPb2qy nIpoV96faaslcssR0b9OxofZPwI080lqQFhbX5Q43DYOCOggLBR+tfBMnZsljd8kbFmNK1u5 0NT0FWMqyXMbEDt7eY3CCIV/A93dKA7Kekwc3az3trUEVWTpsI1XYBNu5eeXcGPzWvwvECZe Kh2vY= X-Talos-CUID: 9a23:QDECY2iwo8ykSk63p9BFOvLYpTJufXLbkXjeExKBFXswV76NZVOM+rpLqp87 X-Talos-MUID: 9a23:r/+4hQ3/pfovs1zasfYq2iiokzUjsoO0VUIvl889htjZZQFqKyelsRSne9py X-IronPort-Anti-Spam-Filtered: true X-IronPort-AV: E=Sophos;i="6.25,207,1779148800"; d="scan'208";a="799172905" Received: from alln-l-core-12.cisco.com ([173.36.16.149]) by alln-iport-4.cisco.com with ESMTP/TLS/TLS_AES_256_GCM_SHA384; 06 Aug 2026 05:51:22 +0000 Received: from sjc-ads-5471.cisco.com (sjc-ads-5471.cisco.com [10.28.23.235]) (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 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "ciscoit-managed-infra-smtp-auth.cisco.com", Issuer "Internal Private TLS SubCA" (verified OK)) by alln-l-core-12.cisco.com (Postfix) with ESMTPS id BBAA11800016D; Thu, 6 Aug 2026 05:51:22 +0000 (GMT) Received: by sjc-ads-5471.cisco.com (Postfix, from userid 1887505) id 67780CC12A6; Wed, 5 Aug 2026 22:51: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, Hetvi Thakar Subject: [meta-python][scarthgap][PATCH 2/5] python3-pyjwt: Fix CVE-2026-48524 Date: Wed, 5 Aug 2026 22:50:58 -0700 Message-Id: <20260806055101.23160-2-hthakar@cisco.com> X-Mailer: git-send-email 2.35.6 In-Reply-To: <20260806055101.23160-1-hthakar@cisco.com> References: <20260806055101.23160-1-hthakar@cisco.com> MIME-Version: 1.0 X-Auto-Response-Suppress: DR, OOF, AutoReply X-Outbound-Client-TLS: VERIFIED;sjc-ads-5471.cisco.com [10.28.23.235];TLSv1.3;TLS_AES_256_GCM_SHA384;256;ciscoit-managed-infra-smtp-auth.cisco.com X-Outbound-SMTP-Client: 10.28.23.235, sjc-ads-5471.cisco.com X-Outbound-Node: alln-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 ; Thu, 06 Aug 2026 05:51:33 -0000 X-Groupsio-URL: https://lists.openembedded.org/g/openembedded-devel/message/128833 From: Hetvi Thakar Preserve a valid cached JWK set when a refresh request fails. The previous finally block stored None on errors, turning a transient JWKS outage into an authentication failure for otherwise cached keys. This patch applies the relevant subset of the upstream 2.13.0 fix. The upstream commit is referenced in [1], and the public advisory is referenced in [2]. [1] https://github.com/jpadilla/pyjwt/commit/95791b1759b8aa4f2203575d344d5c78564cdc81 [2] https://github.com/advisories/GHSA-fhv5-28vv-h8m8 Signed-off-by: Hetvi Thakar --- .../python/python3-pyjwt/CVE-2026-48524.patch | 91 +++++++++++++++++++ .../python/python3-pyjwt_2.8.0.bb | 1 + 2 files changed, 92 insertions(+) create mode 100644 meta-python/recipes-devtools/python/python3-pyjwt/CVE-2026-48524.patch diff --git a/meta-python/recipes-devtools/python/python3-pyjwt/CVE-2026-48524.patch b/meta-python/recipes-devtools/python/python3-pyjwt/CVE-2026-48524.patch new file mode 100644 index 0000000000..4dc49771b4 --- /dev/null +++ b/meta-python/recipes-devtools/python/python3-pyjwt/CVE-2026-48524.patch @@ -0,0 +1,91 @@ +From cb19f697eff2807d28c66639e5ee39cc92de4985 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jos=C3=A9=20Padilla?= +Date: Mon, 3 Aug 2026 03:21:01 -0700 +Subject: [PATCH] PyJWKClient: preserve cached JWKS on fetch errors + +Only replace the cached JWK set after a successful fetch. A failed +refresh previously stored None from the finally block and discarded +valid cached keys. + +CVE: CVE-2026-48524 +Upstream-Status: Backport [https://github.com/jpadilla/pyjwt/commit/95791b1759b8aa4f2203575d344d5c78564cdc81] + +Backport Changes: +- Extracted only the CVE-2026-48524 successful-fetch cache update and + regression test from the bundled upstream 2.13.0 commit. The other + requested CVE fixes are carried as separate patches. +- Adapted the hunk and test locations to PyJWT 2.8.0 and shortened the + upstream explanatory comments without changing behavior or assertions. +- Omitted the 2.13.0 version and changelog updates, CVE-2026-48523 (which + does not affect 2.8.0), and unrelated hardening from the bundled commit. + +(cherry picked from commit 95791b1759b8aa4f2203575d344d5c78564cdc81) +Signed-off-by: Hetvi Thakar +--- + jwt/jwks_client.py | 12 ++++++------ + tests/test_jwks_client.py | 12 ++++++++++-- + 2 files changed, 16 insertions(+), 8 deletions(-) + +diff --git a/jwt/jwks_client.py b/jwt/jwks_client.py +index 18de342..0e7d226 100644 +--- a/jwt/jwks_client.py ++++ b/jwt/jwks_client.py +@@ -59,7 +59,6 @@ class PyJWKClient: + self.get_signing_key = lru_cache(maxsize=max_cached_keys)(self.get_signing_key) # type: ignore + + def fetch_data(self) -> Any: +- jwk_set: Any = None + try: + r = urllib.request.Request(url=self.uri, headers=self.headers) + with urllib.request.urlopen( +@@ -70,11 +69,12 @@ class PyJWKClient: + raise PyJWKClientConnectionError( + f'Fail to fetch data from the url, err: "{e}"' + ) +- else: +- return jwk_set +- finally: +- if self.jwk_set_cache is not None: +- self.jwk_set_cache.put(jwk_set) ++ ++ # Only update the cache on a successful fetch. Writing None from a ++ # finally block on error would discard a previously cached JWKS. ++ if self.jwk_set_cache is not None: ++ self.jwk_set_cache.put(jwk_set) ++ return jwk_set + + def get_jwk_set(self, refresh: bool = False) -> PyJWKSet: + data = None +diff --git a/tests/test_jwks_client.py b/tests/test_jwks_client.py +index d4bdd35..4a836f2 100644 +--- a/tests/test_jwks_client.py ++++ b/tests/test_jwks_client.py +@@ -271,18 +271,26 @@ class TestPyJWKClient: + + assert repeated_call.call_count == 1 + +- def test_get_jwt_set_failed_request_should_clear_cache(self): ++ def test_get_jwt_set_failed_refresh_preserves_cached_jwks(self) -> None: + url = "https://dev-87evx9ru.auth0.com/.well-known/jwks.json" + + jwks_client = PyJWKClient(url) + with mocked_success_response(RESPONSE_DATA_WITH_MATCHING_KID): + jwks_client.get_jwk_set() + ++ assert jwks_client.jwk_set_cache is not None ++ assert jwks_client.jwk_set_cache.get() is not None ++ + with pytest.raises(PyJWKClientError): + with mocked_failed_response(): + jwks_client.get_jwk_set(refresh=True) + +- assert jwks_client.jwk_set_cache is None ++ cached = jwks_client.jwk_set_cache.get() ++ assert cached is not None ++ ++ with mocked_success_response(RESPONSE_DATA_WITH_MATCHING_KID) as call: ++ jwks_client.get_jwk_set() ++ assert call.call_count == 0 + + def test_failed_request_should_raise_connection_error(self): + token = "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6Ik5FRTFRVVJCT1RNNE16STVSa0ZETlRZeE9UVTFNRGcyT0Rnd1EwVXpNVGsxUWpZeVJrUkZRdyJ9.eyJpc3MiOiJodHRwczovL2Rldi04N2V2eDlydS5hdXRoMC5jb20vIiwic3ViIjoiYVc0Q2NhNzl4UmVMV1V6MGFFMkg2a0QwTzNjWEJWdENAY2xpZW50cyIsImF1ZCI6Imh0dHBzOi8vZXhwZW5zZXMtYXBpIiwiaWF0IjoxNTcyMDA2OTU0LCJleHAiOjE1NzIwMDY5NjQsImF6cCI6ImFXNENjYTc5eFJlTFdVejBhRTJINmtEME8zY1hCVnRDIiwiZ3R5IjoiY2xpZW50LWNyZWRlbnRpYWxzIn0.PUxE7xn52aTCohGiWoSdMBZGiYAHwE5FYie0Y1qUT68IHSTXwXVd6hn02HTah6epvHHVKA2FqcFZ4GGv5VTHEvYpeggiiZMgbxFrmTEY0csL6VNkX1eaJGcuehwQCRBKRLL3zKmA5IKGy5GeUnIbpPHLHDxr-GXvgFzsdsyWlVQvPX2xjeaQ217r2PtxDeqjlf66UYl6oY6AqNS8DH3iryCvIfCcybRZkc_hdy-6ZMoKT6Piijvk_aXdm7-QQqKJFHLuEqrVSOuBqqiNfVrG27QzAPuPOxvfXTVLXL2jek5meH6n-VWgrBdoMFH93QEszEDowDAEhQPHVs0xj7SIzA" diff --git a/meta-python/recipes-devtools/python/python3-pyjwt_2.8.0.bb b/meta-python/recipes-devtools/python/python3-pyjwt_2.8.0.bb index 55884cddad..7b72cfb4bd 100644 --- a/meta-python/recipes-devtools/python/python3-pyjwt_2.8.0.bb +++ b/meta-python/recipes-devtools/python/python3-pyjwt_2.8.0.bb @@ -8,6 +8,7 @@ LIC_FILES_CHKSUM = "file://LICENSE;md5=e4b56d2c9973d8cf54655555be06e551" SRC_URI += " \ file://CVE-2026-32597.patch \ file://CVE-2026-48522.patch \ + file://CVE-2026-48524.patch \ " SRC_URI[sha256sum] = "57e28d156e3d5c10088e0c68abb90bfac3df82b40a71bd0daa20c65ccd5c23de" From patchwork Thu Aug 6 05:50:59 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: 94662 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 0EFFBC56208 for ; Thu, 6 Aug 2026 05:51:34 +0000 (UTC) Received: from alln-iport-4.cisco.com (alln-iport-4.cisco.com [173.37.142.91]) by mx.groups.io with SMTP id smtpd.msgproc02-g2.13570.1785995483792386520 for ; Wed, 05 Aug 2026 22:51:26 -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=fJofwtnn; spf=pass (domain: cisco.com, ip: 173.37.142.91, mailfrom: hthakar@cisco.com) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=cisco.com; i=@cisco.com; l=5899; q=dns/txt; s=iport01; t=1785995486; x=1787205086; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=FIrhhcUH0piBRZyetKQadAfAOXNtVd8koGTcjlOolVk=; b=fJofwtnnxoytLHftV6htw5puNa8r/7lZlvWvZ8/Do9QZlmK//cvELFor BZvXGE5KZ3/7dZFw8ezwndT2VFLHhbWZntubFo1Tdg2ILUPJOoh5fuPsd OBfCL+Q/tvIx+q2L5McVuhlaO1VAWa1zEv1Cim7GhLDUczkseCqYT4Drr pyVIcGtpGYiwrMU/+IiQdjjXW/Nzns1K1qdgVP8/8t2xjPHsZqX4gDFXi kqs9piDY3P9A85zIHC5W/Rg0HPJ3RUPr6cm+GW4HCfAa6zHVqFWxyJXXq bfJbGKSb2cDsD1eFq39Np+4tlDFQKUS0gaPGfsg0spHtZvcCp2U/M3FAL w==; X-CSE-ConnectionGUID: U3UxNaFYRV2zoGduKG0K7g== X-CSE-MsgGUID: zY8RHkKnRqC0gaTVmTLfGA== X-IPAS-Result: A0BIAgC3H3Rq/5IQJK1aglmCV3ReQ0mWSgOeG4F+DwEBAQ9EDQQBAYUFAo1mAiY0CQ4BAgQDAgMBAQEBAQEBAQEBAQsBAQUBAQECAQcFgQ4Thk8NhloBAgEDJwsBGAEbEhAcAwECLysjCBmDAgGCdAMRvHGBeTOBAYMoAYFU2y4BCxQBBYEzhT+IIV0YAYR8JxsbgXKBFYNpgQWBXAKIJQSCInoSgVqRFkiBHgNZLAFVEw0KCwcFgWYDNRIqFW4yHYEjPheBDRsHBYEdgSiEaCMZNnqBCV6BLSpkARIXgQmCbwKCeoEpCxgNSBEsNxQZBD5uB41/IIJBAXoTASsXaIEGRaVYoQ8KKIN1jCGVOhozqmwLmH2OCpYBT4RpgWg8gVlwFYMiCUoZD44qDguDYMw5JzICCTIBAQcCBw4DC4FokX4BAQ IronPort-Data: A9a23:JbS/+qnXcIX+vDvABgs+IZbo5gzXJ0RdPkR7XQ2eYbSJt1+Wr1Gzt xIbXW/SbP/bYjehfoskaY+yoRwD7Z7Vy9c3TQVoryo3QltH+JHPbTi7wugcHM8zwunrFh8PA xA2M4GYRCwMZiaC4E/raf658SUUOZigHtLUEPTDNj16WThqQSIgjQMLs+Mii+aEu/Dha++2k Y20+ZC31GONgWYubDpEs//b8nuDgdyr0N8mlg1mDRx0lAe2e0k9VPo3Oay3Jn3kdYhYdsbSb /rD1ryw4lTC9B4rDN6/+p6jGqHdauePVeQmoiM+t5mK2nCulARrukoIHKZ0hXNsttm8t4sZJ OOhGnCHYVxB0qXkwIzxWvTDes10FfUuFLTveRBTvSEPpqHLWyOE/hlgMK05FbBDx/ZRCE9/z 8JCOjciYg2gqLqVn73uH4GAhux7RCXqFIobvnclyXTSCuwrBMiSBa7L/tRfmjw3g6iiH96HO JFfMmQpNUqGOkERUrsUIMpWcOOAhmX/ej5RsnqepLE85C7YywkZPL3Fb4uEI4PQFJ4O9qqej nD3r17ZATIcDsW0kTWMzkypusvBsgquDer+E5X9rJaGmma7wXQeDhATX1a3rfS1z0KzRd9bA 0gV4TY1668q+UqmS9PwUxG1rDiDpBF0ZjZLO+Q+7AfIzu/f5ByUQzBVCDVAc9ch8sQxQFTGy 2O0oj8gPhQ32JX9dJ5X3u78Qe+aUcTNEVI/WA== IronPort-HdrOrdr: A9a23:vYn7J6koa5ynqzA1KDKTLFoKMsPpDfL03DAbv31ZSRFFG/FwWf rAoB19726StN9/YhAdcLy7VZVoBEmsl6KdgrNhWYtKIjOHhILAFugLhuHfKn/bakjDH4Vmu5 uIHZITNDTYNykdsS+D2njaL/8QhP+a7auvmeDSi11pTQ1sduVcyj0RMHfjLqWzLzM2fqbQ0/ Gnl7J6mwY= X-Talos-CUID: 9a23:teyZRG5usYGy0RuzJNssyRUpCuYsXEzn8i3CJGC0FEVGEJ7KRgrF X-Talos-MUID: 9a23:5aW5DgV1+XDKp1jq/C3d1AtCN+Ru2b2FUE8ErasDh+2KGgUlbg== X-IronPort-Anti-Spam-Filtered: true X-IronPort-AV: E=Sophos;i="6.25,207,1779148800"; d="scan'208";a="799172933" Received: from alln-l-core-09.cisco.com ([173.36.16.146]) by alln-iport-4.cisco.com with ESMTP/TLS/TLS_AES_256_GCM_SHA384; 06 Aug 2026 05:51:25 +0000 Received: from sjc-ads-5471.cisco.com (sjc-ads-5471.cisco.com [10.28.23.235]) (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 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "ciscoit-managed-infra-smtp-auth.cisco.com", Issuer "Internal Private TLS SubCA" (verified OK)) by alln-l-core-09.cisco.com (Postfix) with ESMTPS id C0AF71800021B; Thu, 6 Aug 2026 05:51:25 +0000 (GMT) Received: by sjc-ads-5471.cisco.com (Postfix, from userid 1887505) id 6BF7BCC12A6; Wed, 5 Aug 2026 22:51:25 -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, Hetvi Thakar Subject: [meta-python][scarthgap][PATCH 3/5] python3-pyjwt: Fix CVE-2026-48525 Date: Wed, 5 Aug 2026 22:50:59 -0700 Message-Id: <20260806055101.23160-3-hthakar@cisco.com> X-Mailer: git-send-email 2.35.6 In-Reply-To: <20260806055101.23160-1-hthakar@cisco.com> References: <20260806055101.23160-1-hthakar@cisco.com> MIME-Version: 1.0 X-Auto-Response-Suppress: DR, OOF, AutoReply X-Outbound-Client-TLS: VERIFIED;sjc-ads-5471.cisco.com [10.28.23.235];TLSv1.3;TLS_AES_256_GCM_SHA384;256;ciscoit-managed-infra-smtp-auth.cisco.com X-Outbound-SMTP-Client: 10.28.23.235, sjc-ads-5471.cisco.com X-Outbound-Node: alln-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 ; Thu, 06 Aug 2026 05:51:34 -0000 X-Groupsio-URL: https://lists.openembedded.org/g/openembedded-devel/message/128834 From: Hetvi Thakar Reject a non-empty compact payload segment for b64=false tokens before Base64URL decoding. The segment is unused for detached JWS verification, so decoding it allowed unauthenticated CPU and memory consumption. This patch applies the relevant subset of the upstream 2.13.0 fix. The upstream commit is referenced in [1], and the public advisory is referenced in [2]. [1] https://github.com/jpadilla/pyjwt/commit/95791b1759b8aa4f2203575d344d5c78564cdc81 [2] https://github.com/advisories/GHSA-w7vc-732c-9m39 Signed-off-by: Hetvi Thakar --- .../python/python3-pyjwt/CVE-2026-48525.patch | 115 ++++++++++++++++++ .../python/python3-pyjwt_2.8.0.bb | 1 + 2 files changed, 116 insertions(+) create mode 100644 meta-python/recipes-devtools/python/python3-pyjwt/CVE-2026-48525.patch diff --git a/meta-python/recipes-devtools/python/python3-pyjwt/CVE-2026-48525.patch b/meta-python/recipes-devtools/python/python3-pyjwt/CVE-2026-48525.patch new file mode 100644 index 0000000000..c43e576118 --- /dev/null +++ b/meta-python/recipes-devtools/python/python3-pyjwt/CVE-2026-48525.patch @@ -0,0 +1,115 @@ +From 91ac94bdc85d24c6d35a5f6cdd58eb8c6c4df0f0 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jos=C3=A9=20Padilla?= +Date: Mon, 3 Aug 2026 03:21:30 -0700 +Subject: [PATCH] api_jws: reject non-empty detached payload segments + +For b64=false tokens, reject a non-empty compact payload segment before +Base64URL decoding. The segment is unused when detached_payload is +supplied, so decoding attacker-controlled data only consumes CPU and +memory. + +CVE: CVE-2026-48525 +Upstream-Status: Backport [https://github.com/jpadilla/pyjwt/commit/95791b1759b8aa4f2203575d344d5c78564cdc81] + +Backport Changes: +- Extracted only the CVE-2026-48525 detached-payload segment check and + regression test from the bundled upstream 2.13.0 commit. The other + requested CVE fixes are carried as separate patches. +- Adapted the hunk and test locations to PyJWT 2.8.0, used module-level + hashlib and hmac imports, and shortened explanatory comments without + changing the tested behavior. +- Excluded the separate RFC 7797 b64/crit hardening bundled upstream. +- Omitted the 2.13.0 version and changelog updates, CVE-2026-48523 (which + does not affect 2.8.0), and unrelated hardening from the bundled commit. + +(cherry picked from commit 95791b1759b8aa4f2203575d344d5c78564cdc81) +Signed-off-by: Hetvi Thakar +--- + jwt/api_jws.py | 17 +++++++++++++---- + tests/test_api_jws.py | 34 +++++++++++++++++++++++++++++++++- + 2 files changed, 46 insertions(+), 5 deletions(-) + +diff --git a/jwt/api_jws.py b/jwt/api_jws.py +index 1750442..0d5ab2b 100644 +--- a/jwt/api_jws.py ++++ b/jwt/api_jws.py +@@ -274,10 +274,19 @@ class PyJWS: + if not isinstance(header, dict): + raise DecodeError("Invalid header string: must be a json object") + +- try: +- payload = base64url_decode(payload_segment) +- except (TypeError, binascii.Error) as err: +- raise DecodeError("Invalid payload padding") from err ++ if header.get("b64", True) is False: ++ # Detached compact serialization requires an empty payload ++ # segment. Reject it before decoding attacker-controlled data. ++ if payload_segment: ++ raise DecodeError( ++ "Payload segment must be empty when 'b64' is false." ++ ) ++ payload = b"" ++ else: ++ try: ++ payload = base64url_decode(payload_segment) ++ except (TypeError, binascii.Error) as err: ++ raise DecodeError("Invalid payload padding") from err + + try: + signature = base64url_decode(crypto_segment) +diff --git a/tests/test_api_jws.py b/tests/test_api_jws.py +index 434874b..29f84a7 100644 +--- a/tests/test_api_jws.py ++++ b/tests/test_api_jws.py +@@ -1,3 +1,5 @@ ++import hashlib ++import hmac + import json + from decimal import Decimal + +@@ -11,7 +13,7 @@ from jwt.exceptions import ( + InvalidSignatureError, + InvalidTokenError, + ) +-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, no_crypto_required +@@ -766,6 +768,36 @@ class TestJWS: + assert "b64" not in msg_header_obj + assert msg_payload + ++ def test_decode_b64_false_rejects_non_empty_payload_segment( ++ self, jws: PyJWS, payload: bytes ++ ) -> None: ++ secret = "secret" ++ header = { ++ "typ": "JWT", ++ "alg": "HS256", ++ "b64": False, ++ "crit": ["b64"], ++ } ++ encoded_header = base64url_encode( ++ json.dumps(header, separators=(",", ":")).encode() ++ ) ++ attacker_segment = b"A" * 1024 ++ signing_input = b".".join([encoded_header, payload]) ++ signature = hmac.new( ++ secret.encode(), signing_input, hashlib.sha256 ++ ).digest() ++ token = b".".join( ++ [encoded_header, attacker_segment, base64url_encode(signature)] ++ ).decode() ++ ++ with pytest.raises(DecodeError, match="Payload segment must be empty"): ++ jws.decode( ++ token, ++ secret, ++ algorithms=["HS256"], ++ detached_payload=payload, ++ ) ++ + def test_decode_detached_content_without_proper_argument(self, jws): + example_jws = ( + "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiIsImI2NCI6ZmFsc2V9" diff --git a/meta-python/recipes-devtools/python/python3-pyjwt_2.8.0.bb b/meta-python/recipes-devtools/python/python3-pyjwt_2.8.0.bb index 7b72cfb4bd..fc3e0bc31d 100644 --- a/meta-python/recipes-devtools/python/python3-pyjwt_2.8.0.bb +++ b/meta-python/recipes-devtools/python/python3-pyjwt_2.8.0.bb @@ -9,6 +9,7 @@ SRC_URI += " \ file://CVE-2026-32597.patch \ file://CVE-2026-48522.patch \ file://CVE-2026-48524.patch \ + file://CVE-2026-48525.patch \ " SRC_URI[sha256sum] = "57e28d156e3d5c10088e0c68abb90bfac3df82b40a71bd0daa20c65ccd5c23de" From patchwork Thu Aug 6 05:51:00 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: 94660 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 E7DAAC55838 for ; Thu, 6 Aug 2026 05:51:33 +0000 (UTC) Received: from alln-iport-7.cisco.com (alln-iport-7.cisco.com [173.37.142.94]) by mx.groups.io with SMTP id smtpd.msgproc01-g2.13113.1785995489081352051 for ; Wed, 05 Aug 2026 22:51:29 -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=Eb8VOEq/; spf=pass (domain: cisco.com, ip: 173.37.142.94, mailfrom: hthakar@cisco.com) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=cisco.com; i=@cisco.com; l=5034; q=dns/txt; s=iport01; t=1785995489; x=1787205089; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=mUydsJW6QMzVznEqTelXm++5wEJGKl8GT9EHb7XDBN0=; b=Eb8VOEq/TYgxRx/zQoH0MvlvjR1iA40IEOrKOSVSJ8KCI2Uz97ju6i4l Uq+wYy5ReM/GLSqmsyQgcUObSLnPO8PdMA6KSzWs6BBnYcKkVexyvA24F cGypOg2iT6kG1Vl0qEY/PwUuoVCunE1t/rvKbvw6F68c4WdW3xLqzC/pg +VEZkfV+n4KfRVOUABBXGjOeORKgZO1AzDZGeTk1bqI3WfDNzHHj82VL+ av8grb451AHPdGyg8JCKVe1EvcvKMCVfNG6GwDiWHd8+z1QFtGVkA5a5n BGRWfD4fU5A21k/1DPTYg6DfZZS6o6bSsq1g/mNa4MZDx/GLGyJWGcF5h w==; X-CSE-ConnectionGUID: /lVJyTC8Qtqa50Wal0Cnkg== X-CSE-MsgGUID: DEqH5WOBTgKOIMw11nmYJQ== X-IPAS-Result: A0BIAgA8IHRq/40QJK1aglmCV3ReQ0mWSgOeG4F+DwEBAQ9EDQQBAYUFAo1mAiY0CQ4BAgQDAgMBAQEBAQEBAQEBAQsBAQUBAQECAQcFgQ4Thk8NhloBAgEDJwsBGAEbEhAcAwECLysjCBmDAgGCdAMRvHKBeTOBAYMoAYFU2y4BCxQBBYEzhT+IIV0YAUSEOCcbG4FygRWDaYEFgVwCiCUEgiJ6EoFakRZIgR4DWSwBVRMNCgsHBYFmAzUSKhVuMh2BIz4XgQ0bBwWBHYEohGgjGTZ6gQlegS0qZAESF4EJgm8CgnqBKQsYDUgRLDcUGQQ+bgeNfyCCQWQqASt/EoE5pVihDwoog3WMIZU6GjOEBIFXkkCSUQuYfY4KlgEFSoRpgWg8gVlwFYMiCUoZD444g2uFZMZVJzICCTIBAQcCBw4DC4FokAItgU8BAQ IronPort-Data: A9a23:NjADFqkfXDKMN1ZifvecGs/o5gzXJ0RdPkR7XQ2eYbSJt1+Wr1Gzt xIYWziBMvfcYmqjfY0iPdznoxsHvsLTz4Q2HgA/rylhRFtH+JHPbTi7wugcHM8zwunrFh8PA xA2M4GYRCwMZiaC4E/raf658SUUOZigHtLUEPTDNj16WThqQSIgjQMLs+Mii+aEu/Dha++2k Y20+ZC31GONgWYubDpEs//b8nuDgdyr0N8mlg1mDRx0lAe2e0k9VPo3Oay3Jn3kdYhYdsbSb /rD1ryw4lTC9B4rDN6/+p6jGqHdauePVeQmoiM+t5mK2nCulARrukoIHKZ0hXNsttm8t4sZJ OOhGnCHYVxB0qXkwIzxWvTDes10FfUuFLTveRBTvSEPpqHLWyOE/hlgMK05FcocxMRmPUoez OABIW1VURmH38mww73uH4GAhux7RCXqFIobvnclyXTSCuwrBMifBa7L/tRfmjw3g6iiH96HO JFfMmQpNUqGOkEWUrsUIMpWcOOAhmX/ej5RsnqepLE85C7YywkZPL3Fb4uFJoXUG5wF9qqej k7r5kSkPTYwCNO87hug7Sv1gOr+vxquDer+E5X9rJaGmma7wXQeDhATX1a3rfS1z0KzRd9bA 0gV4TY1668q+UqmS9PwUxG1rDiDpBF0ZjZLO+Q+7AfIzu/f5ByUQzBYCDVAc9ch8sQxQFTGy 2O0oj8gPhQ32JX9dJ5X3u78Qe+aUcTNEVI/WA== IronPort-HdrOrdr: A9a23:u11c8KOaBNtJVsBcThmjsMiBIKoaSvp037Dk7S9MoHtuA6ulfq +V/cjzuSWYtN9VYgBDpTniAtjlfZqjz/5ICOAqVN/INjUO+lHYSb2KhrGN/9SPIUHDH8dmpM FdmtBFeb7NJGk/q9rm6w+lFNtl6tyG/Ke0wdr69R5WPHhXg2UK1XYDNu5deXcGPDV7OQ== X-Talos-CUID: 9a23:K18NdmNSOSjroO5DHy1Z1l8oMZAcbmTUkS/vKkvgImBqR+jA X-Talos-MUID: 9a23:dqmrygqbOSoqP2o7mlUezx1PLec13IOENE8utrQjpJDdMylBGQ7I2Q== X-IronPort-Anti-Spam-Filtered: true X-IronPort-AV: E=Sophos;i="6.25,207,1779148800"; d="scan'208";a="798416618" Received: from alln-l-core-04.cisco.com ([173.36.16.141]) by alln-iport-7.cisco.com with ESMTP/TLS/TLS_AES_256_GCM_SHA384; 06 Aug 2026 05:51:28 +0000 Received: from sjc-ads-5471.cisco.com (sjc-ads-5471.cisco.com [10.28.23.235]) (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 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "ciscoit-managed-infra-smtp-auth.cisco.com", Issuer "Internal Private TLS SubCA" (verified OK)) by alln-l-core-04.cisco.com (Postfix) with ESMTPS id 1117418000183; Thu, 6 Aug 2026 05:51:28 +0000 (GMT) Received: by sjc-ads-5471.cisco.com (Postfix, from userid 1887505) id B0A87CC12A6; Wed, 5 Aug 2026 22:51:27 -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, Hetvi Thakar Subject: [meta-python][scarthgap][PATCH 4/5] python3-pyjwt: Fix CVE-2026-48526 Date: Wed, 5 Aug 2026 22:51:00 -0700 Message-Id: <20260806055101.23160-4-hthakar@cisco.com> X-Mailer: git-send-email 2.35.6 In-Reply-To: <20260806055101.23160-1-hthakar@cisco.com> References: <20260806055101.23160-1-hthakar@cisco.com> MIME-Version: 1.0 X-Auto-Response-Suppress: DR, OOF, AutoReply X-Outbound-Client-TLS: VERIFIED;sjc-ads-5471.cisco.com [10.28.23.235];TLSv1.3;TLS_AES_256_GCM_SHA384;256;ciscoit-managed-infra-smtp-auth.cisco.com X-Outbound-SMTP-Client: 10.28.23.235, sjc-ads-5471.cisco.com X-Outbound-Node: alln-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 ; Thu, 06 Aug 2026 05:51:33 -0000 X-Groupsio-URL: https://lists.openembedded.org/g/openembedded-devel/message/128835 From: Hetvi Thakar Reject JSON Web Key documents passed directly as HMAC secrets. This prevents public asymmetric JWK data from being reused as an HMAC key when an application permits mixed symmetric and asymmetric algorithms. This patch applies the relevant subset of the upstream 2.13.0 fix. The upstream commit is referenced in [1], and the public advisory is referenced in [2]. [1] https://github.com/jpadilla/pyjwt/commit/95791b1759b8aa4f2203575d344d5c78564cdc81 [2] https://github.com/advisories/GHSA-xgmm-8j9v-c9wx Signed-off-by: Hetvi Thakar --- .../python/python3-pyjwt/CVE-2026-48526.patch | 87 +++++++++++++++++++ .../python/python3-pyjwt_2.8.0.bb | 1 + 2 files changed, 88 insertions(+) create mode 100644 meta-python/recipes-devtools/python/python3-pyjwt/CVE-2026-48526.patch diff --git a/meta-python/recipes-devtools/python/python3-pyjwt/CVE-2026-48526.patch b/meta-python/recipes-devtools/python/python3-pyjwt/CVE-2026-48526.patch new file mode 100644 index 0000000000..6cde3ccce3 --- /dev/null +++ b/meta-python/recipes-devtools/python/python3-pyjwt/CVE-2026-48526.patch @@ -0,0 +1,87 @@ +From 9d2064bccc0ac60884906d9dd89ace589f9f8281 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jos=C3=A9=20Padilla?= +Date: Mon, 3 Aug 2026 03:22:08 -0700 +Subject: [PATCH] algorithms: reject raw JWK documents as HMAC secrets + +Reject JSON Web Key documents passed directly to +HMACAlgorithm.prepare_key. Public asymmetric JWK data must not be +accepted as an HMAC secret when callers permit mixed algorithm families. + +CVE: CVE-2026-48526 +Upstream-Status: Backport [https://github.com/jpadilla/pyjwt/commit/95791b1759b8aa4f2203575d344d5c78564cdc81] + +Backport Changes: +- Extracted only the CVE-2026-48526 raw-JWK rejection and regression tests + from the bundled upstream 2.13.0 commit. The other requested CVE fixes + are carried as separate patches. +- Adapted the hunk and test locations to PyJWT 2.8.0, renamed the upstream + local variable `jwk_obj` to `jwk`, and omitted explanatory comments; + the validation logic and assertions are unchanged. +- Excluded the separate empty-HMAC-key hardening bundled in the same file. +- Omitted the 2.13.0 version and changelog updates, CVE-2026-48523 (which + does not affect 2.8.0), and unrelated hardening from the bundled commit. + +(cherry picked from commit 95791b1759b8aa4f2203575d344d5c78564cdc81) +Signed-off-by: Hetvi Thakar +--- + jwt/algorithms.py | 13 +++++++++++++ + tests/test_algorithms.py | 22 ++++++++++++++++++++++ + 2 files changed, 35 insertions(+) + +diff --git a/jwt/algorithms.py b/jwt/algorithms.py +index ed18715..b6303ed 100644 +--- a/jwt/algorithms.py ++++ b/jwt/algorithms.py +@@ -270,6 +270,19 @@ class HMACAlgorithm(Algorithm): + " should not be used as an HMAC secret." + ) + ++ stripped = key_bytes.lstrip() ++ if stripped.startswith(b"{"): ++ try: ++ jwk = json.loads(key_bytes) ++ except ValueError: ++ jwk = None ++ if isinstance(jwk, dict) and "kty" in jwk: ++ raise InvalidKeyError( ++ "The specified key looks like a JWK and should not be " ++ "used directly as an HMAC secret. Load it via " ++ "PyJWK / HMACAlgorithm.from_jwk first." ++ ) ++ + return key_bytes + + @overload +diff --git a/tests/test_algorithms.py b/tests/test_algorithms.py +index 1a39552..e5220c6 100644 +--- a/tests/test_algorithms.py ++++ b/tests/test_algorithms.py +@@ -108,6 +108,28 @@ class TestAlgorithms: + with pytest.raises(InvalidKeyError): + algo.from_jwk(keyfile.read()) + ++ @pytest.mark.parametrize( ++ "jwk_file", ++ [ ++ "jwk_rsa_pub.json", ++ "jwk_ec_pub_P-256.json", ++ "jwk_okp_pub_Ed25519.json", ++ "jwk_hmac.json", ++ ], ++ ) ++ def test_hmac_prepare_key_rejects_jwk_json(self, jwk_file: str) -> None: ++ algo = HMACAlgorithm(HMACAlgorithm.SHA256) ++ ++ with open(key_path(jwk_file)) as keyfile: ++ with pytest.raises(InvalidKeyError, match="looks like a JWK"): ++ algo.prepare_key(keyfile.read()) ++ ++ def test_hmac_prepare_key_accepts_json_without_kty(self) -> None: ++ algo = HMACAlgorithm(HMACAlgorithm.SHA256) ++ ++ key = algo.prepare_key('{"this": "is just a json-shaped secret"}') ++ assert key == b'{"this": "is just a json-shaped secret"}' ++ + @crypto_required + def test_rsa_should_parse_pem_public_key(self): + algo = RSAAlgorithm(RSAAlgorithm.SHA256) diff --git a/meta-python/recipes-devtools/python/python3-pyjwt_2.8.0.bb b/meta-python/recipes-devtools/python/python3-pyjwt_2.8.0.bb index fc3e0bc31d..3804d8ab72 100644 --- a/meta-python/recipes-devtools/python/python3-pyjwt_2.8.0.bb +++ b/meta-python/recipes-devtools/python/python3-pyjwt_2.8.0.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 \ " SRC_URI[sha256sum] = "57e28d156e3d5c10088e0c68abb90bfac3df82b40a71bd0daa20c65ccd5c23de" From patchwork Thu Aug 6 05:51:01 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: 94663 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 09888C55ABF for ; Thu, 6 Aug 2026 05:51:54 +0000 (UTC) Received: from alln-iport-8.cisco.com (alln-iport-8.cisco.com [173.37.142.95]) by mx.groups.io with SMTP id smtpd.msgproc01-g2.13114.1785995511396216566 for ; Wed, 05 Aug 2026 22:51:51 -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=ih74iBxe; spf=pass (domain: cisco.com, ip: 173.37.142.95, mailfrom: hthakar@cisco.com) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=cisco.com; i=@cisco.com; l=14833; q=dns/txt; s=iport01; t=1785995511; x=1787205111; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=Mn/MGvpRGi12zNJJxbRAK2qJ4h9NAYwWr/AO0VbJPmY=; b=ih74iBxeTB/RCV14Bg+gGNCm0DuF5450Zbz0kit4kk0AjaSvXUTzdTQq Qnbcm42BFCavCq9E+HdY32M7HPOqw7aOentxybP6U1rQ5tqgm1Dhkj1Tc w8N9GTl8uc+fwo6AGp99LZn2R6Tyyu9sGvGZ9MxTRMlTA3S+ZY2bDIjfq Ibo4NzEyFwF3Nx4fN71Yb3pwyVQhrnUh7VDRcp1miLUU+cnBI5Mxn+bgH 3zOL/iNqwvWM1+A9dv8P46N55CK5kz1sWL4QoSN2NUdcVASynHm+Cl4Fs Ag9gLdmbiquQ381jciEDADFIEUmriYUA2foIJ8iolhCK2f2TB0lr3wcrr A==; X-CSE-ConnectionGUID: th0LdhjvQZa9dUbyKo3ffg== X-CSE-MsgGUID: /Ky255y5QwKo0/muNkNYig== X-IPAS-Result: A0BLAgC5IHRq/4wQJK1aglmCV3ReQ0mVXmwDgROKUYVmjFEUgWoPAQEBD0QNBAEBhD9GAo1mAiY0CQ4BAgQDAgMBAQEBAQEBAQEBAQsBAQUBAQECAQcFgQ4Thk8NhloBAgEDJwsBGAEtEBwDAQIvIAsjCBkagmgBgjoDNwMRvHSBeTOBAYJmQgGBVNhJDYFJgQ8BCxQBBYEzhT+CfoUjXRgBRIQ4JxsbgXKBFYJzdoEFgRpCAoEnEQ+GXgSCDRWBDIFaHoEteGKDR4NcA4ZLSIEeA1ksAVUTDQoLBwWBZgM1EioVbjIdgSM+F4ENGwcFgR2BKIRoIxk2eoEJXoEtKmQBEheBCYJvAoJ6gSkLGA1IESw3FBkEPm4HjX8ggU5TDhIBFRdhAQckRgIzChQHLQgXAR4VGzySbAERkAyCIYpzlF5NcQoog3WMIY8+hXwaM4QEgVeSQJJRC5h9jgqECZIFQoRpgWg8gVlwFTuCZwlKGQ9WjVQECguDYIRQQ1HGVScyAgkyAQEHAgcOAwuBaJAAASeBVgEB IronPort-Data: A9a23:lgPvRqx5hMRL+zpuBrV6t+dhxyrEfRIJ4+MujC+fZmUNrF6WrkUCm GtMXDiCPP3cazT0ft5wbN+19koDuZ6Bz9NiTQY4/lhgHilAwSbn6Xt1DatR0we6dJCroJdPt p1GAjX4BJlqCCea/VH1buSJQUBUjcmgXqD7BPPPJhd/TAplTDZJoR94kobVuKYw6TSCK13L4 46aT/H3Ygf/hWYkaj9MscpvlTs21BjMkGJA1rABTagjUG/2zxE9EJ8ZLKetGHr0KqE8NvK6X evK0Iai9Wrf+Ro3Yvv9+losWhRXKlJ6FVHmZkt+A8BOsDAbzsAB+vpT2M4nVKtio27hc+adZ zl6ncfYpQ8BZsUgkQmGOvVSO3kW0aZuoNcrLZUj2CCe5xWuTpfi/xlhJF02ZakU+uRpOFNHp PAlIiEuaUuNie3jldpXSsE07igiBMDvOIVavjRryivUSK59B5vCWK7No9Rf2V/chOgXQq2YP JRfMGQpNUiYC/FMEg9/5JYWnPuoj3r2aRVTqUmeouw85G27IAlZgOC1aIeEJozSLSlTtgG7t zibonWkOw45M4TYzCej8VSdh+CayEsXX6pXTtVU7MVCh0WewGEWAhAaWVa35PW0lEO6c9ZeM FAPvC02oK4/8UamQtXwU1u/unHsg/IHc9NUF+t/7ESGzbDZpl7CQGMFVTVGLtchsafaWAAX6 7NApPuxbRQHjVFfYSn1Gmu8xd9qBRUoEA== IronPort-HdrOrdr: A9a23:pLhydKDDcHHKFM7lHel055DYdb4zR+YMi2TDGXofdfUzSL3+qy nAppUmPHPP5Qr5HUtQ++xoW5PwJU80i6QU3WB5B97LN2PbUSmTXeRfBODZrQEIdReTygd179 YHT0EHMqySMXFKyeDn/QK/D9EshPOD8KyumKPi6k0Fd3ASV0mlhD0JcTpy1SZNNXF7OaY= X-Talos-CUID: 9a23:4wPeHmB8NGVgLCT6EzVnrGoYGsI7S0/UnXvtKV6bDj1nRrLAHA== X-Talos-MUID: 9a23:bHYGDAkPPasYRx9PWFafdnolF9Yyvvm/VXkSspJe/MyZEy9WCjaS2WE= X-IronPort-Anti-Spam-Filtered: true X-IronPort-AV: E=Sophos;i="6.25,207,1779148800"; d="scan'208";a="800059480" Received: from alln-l-core-03.cisco.com ([173.36.16.140]) by alln-iport-8.cisco.com with ESMTP/TLS/TLS_AES_256_GCM_SHA384; 06 Aug 2026 05:51:30 +0000 Received: from sjc-ads-5471.cisco.com (sjc-ads-5471.cisco.com [10.28.23.235]) (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 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "ciscoit-managed-infra-smtp-auth.cisco.com", Issuer "Internal Private TLS SubCA" (verified OK)) by alln-l-core-03.cisco.com (Postfix) with ESMTPS id 4AF101800042F; Thu, 6 Aug 2026 05:51:30 +0000 (GMT) Received: by sjc-ads-5471.cisco.com (Postfix, from userid 1887505) id EA517CC12A6; Wed, 5 Aug 2026 22:51:29 -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, Hetvi Thakar Subject: [meta-python][scarthgap][PATCH 5/5] python3-twisted: Fix CVE-2026-42304 Date: Wed, 5 Aug 2026 22:51:01 -0700 Message-Id: <20260806055101.23160-5-hthakar@cisco.com> X-Mailer: git-send-email 2.35.6 In-Reply-To: <20260806055101.23160-1-hthakar@cisco.com> References: <20260806055101.23160-1-hthakar@cisco.com> MIME-Version: 1.0 X-Auto-Response-Suppress: DR, OOF, AutoReply X-Outbound-Client-TLS: VERIFIED;sjc-ads-5471.cisco.com [10.28.23.235];TLSv1.3;TLS_AES_256_GCM_SHA384;256;ciscoit-managed-infra-smtp-auth.cisco.com X-Outbound-SMTP-Client: 10.28.23.235, sjc-ads-5471.cisco.com X-Outbound-Node: alln-l-core-03.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 ; Thu, 06 Aug 2026 05:51:54 -0000 X-Groupsio-URL: https://lists.openembedded.org/g/openembedded-devel/message/128836 From: Hetvi Thakar This patch applies the upstream 26.4.0rc2 backport for CVE-2026-42304. The upstream fix merge is referenced in [1], and the public CVE advisory is referenced in [2]. The individual backported commit links are recorded in the embedded patch header because the fix expands to multiple commits. [1] https://github.com/twisted/twisted/commit/2d196123264efb0027eecfe1b430be4a9babdbd8 [2] https://github.com/advisories/GHSA-grgv-6hw6-v9g4 Signed-off-by: Hetvi Thakar --- .../python3-twisted/CVE-2026-42304.patch | 369 ++++++++++++++++++ .../python/python3-twisted_24.3.0.bb | 2 +- 2 files changed, 370 insertions(+), 1 deletion(-) create mode 100644 meta-python/recipes-devtools/python/python3-twisted/CVE-2026-42304.patch diff --git a/meta-python/recipes-devtools/python/python3-twisted/CVE-2026-42304.patch b/meta-python/recipes-devtools/python/python3-twisted/CVE-2026-42304.patch new file mode 100644 index 0000000000..e43ae68977 --- /dev/null +++ b/meta-python/recipes-devtools/python/python3-twisted/CVE-2026-42304.patch @@ -0,0 +1,369 @@ +From 6a1c3399c54a874673a565601bac999ab400c666 Mon Sep 17 00:00:00 2001 +From: Adi Roiban +Date: Wed, 29 Apr 2026 16:03:39 +0100 +Subject: [PATCH] Merge commit from fork + +names: mitigate DNS compression-pointer flood (GHSA-grgv-6hw6-v9g4) + +CVE: CVE-2026-42304 +Upstream-Status: Backport [https://github.com/twisted/twisted/commit/2d196123264efb0027eecfe1b430be4a9babdbd8] + +Backport Changes: +- Expanded the upstream merge and applied its complete first-parent code + and regression-test changes. +- The expanded dependency sequence is be71ecaa113f642f03083bd5ed33af47c59308c8, + 86e1b5490de5baa8ca284d1e6f4f0ade3e8ad7e0, + c75d44ed81b47f8086ed801cfcdb2568b0b32301, + d7d81e08d46b3f266963ea77e5f6b4a333af455f, + 9df6d960d3569751ebb5567093fe1d1d9f63ca54, and + 9ca319ebf61386dd33354c4ade3946ef84ad58fb. +- Retained Scarthgap's `typing.Sequence` import instead of the newer + `collections.abc.Sequence` import. +- Omitted the release-news fragment; it does not affect the fix. + +(cherry picked from commit 2d196123264efb0027eecfe1b430be4a9babdbd8) +Signed-off-by: Hetvi Thakar +--- + src/twisted/names/dns.py | 160 ++++++++++++++++++++++++++--- + src/twisted/names/test/test_dns.py | 85 +++++++++++++++ + 2 files changed, 230 insertions(+), 15 deletions(-) + +diff --git a/src/twisted/names/dns.py b/src/twisted/names/dns.py +index c7644ef50..4d093720d 100644 +--- a/src/twisted/names/dns.py ++++ b/src/twisted/names/dns.py +@@ -11,10 +11,12 @@ Future Plans: + from __future__ import annotations + + # System imports ++import contextvars + import inspect + import random + import socket + import struct ++from contextlib import contextmanager + from io import BytesIO + from itertools import chain + from typing import Optional, Sequence, SupportsInt, Union, overload +@@ -126,6 +128,7 @@ __all__ = [ + "OP_UPDATE", + "PORT", + "AuthoritativeDomainError", ++ "DNSDecodeError", + "DNSQueryTimeoutError", + "DomainError", + ] +@@ -444,6 +447,87 @@ def readPrecisely(file, l): + return buff + + ++class DNSDecodeError(ValueError): ++ """ ++ Raised when a DNS message cannot be decoded because it violates a ++ protocol-level safety limit. ++ """ ++ ++ ++class _DecodeContext: ++ """ ++ Mutable state shared between the L{IEncodable} decoders invoked while ++ reading a single DNS message. ++ ++ The primary purpose is to bound the total number of compression-pointer ++ jumps taken across every name in the message, defending against packets ++ that fan out thousands of records pointing to deeply chained pointers. ++ ++ This class is private. External callers must not rely on it; the ++ per-message scope is installed and torn down by L{Message.decode} ++ through L{_decodeContextVar}. ++ ++ @ivar jumps: The number of compression pointers followed so far. ++ @ivar maxJumps: The inclusive upper bound on L{jumps}. Exceeding it ++ causes L{registerJump} to raise L{DNSDecodeError}. ++ """ ++ ++ __slots__ = ("jumps", "maxJumps") ++ ++ def __init__(self, maxJumps: int = 1000) -> None: ++ self.jumps = 0 ++ self.maxJumps = maxJumps ++ ++ def registerJump(self) -> None: ++ """ ++ Record that a compression pointer has been followed. ++ ++ The check is performed before any further bytes are read so the ++ caller fails fast as soon as the aggregate limit is breached, even ++ if additional records remain in the buffer. ++ ++ @raise DNSDecodeError: if the cumulative number of jumps exceeds ++ L{maxJumps}. ++ """ ++ self.jumps += 1 ++ if self.jumps > self.maxJumps: ++ raise DNSDecodeError( ++ "Too many compression pointers while decoding DNS message " ++ f"(limit is {self.maxJumps})" ++ ) ++ ++ ++# Private module-level L{contextvars.ContextVar} used to share a single ++# L{_DecodeContext} across the re-entrant calls performed while decoding one ++# DNS message. L{contextvars} (rather than a plain module attribute) is used ++# on purpose: although Twisted's reactor is single-threaded, message decoding ++# is re-entrant across many records in a single pass and L{ContextVar} ++# guarantees the scope is restored correctly on exit -- and remains isolated ++# per-task should a future caller decode messages from multiple ++# L{asyncio}-style contexts concurrently. ++_decodeContextVar: contextvars.ContextVar[_DecodeContext | None] = ( ++ contextvars.ContextVar("_dnsDecodeContext", default=None) ++) ++ ++ ++@contextmanager ++def _installDecodeContext(context: _DecodeContext): ++ """ ++ Install C{context} on L{_decodeContextVar} for the duration of the ++ C{with} block and restore the previous value on exit. ++ ++ This wraps the L{contextvars.ContextVar.set} / L{contextvars.ContextVar.reset} ++ token dance so call sites can use a plain C{with} statement. ++ ++ @param context: The L{_DecodeContext} to install as the active context. ++ """ ++ token = _decodeContextVar.set(context) ++ try: ++ yield context ++ finally: ++ _decodeContextVar.reset(token) ++ ++ + class IEncodable(Interface): + """ + Interface for something which can be encoded to and decoded +@@ -549,8 +633,17 @@ class Name: + + @ivar name: A byte string giving the name. + @type name: L{bytes} ++ ++ @ivar maxCompressionPointers: Per-message cap on the total number of ++ compression-pointer dereferences L{decode} will follow before ++ raising L{DNSDecodeError}. Defaults to C{1000}. Override it on ++ a subclass or individual instance to tune the trade-off between ++ tolerance for legitimately verbose messages and resistance to ++ denial-of-service attacks. + """ + ++ maxCompressionPointers: int = 1000 ++ + def __init__(self, name: bytes | str = b""): + """ + @param name: A name. +@@ -595,16 +688,33 @@ class Name: + """ + Decode a byte string into this Name. + ++ When invoked from L{Message.decode}, a shared compression-pointer ++ counter is picked up transparently from the private ++ L{_decodeContextVar}. Standalone callers get a fresh per-call ++ counter seeded from L{maxCompressionPointers}, so existing code ++ keeps working unchanged while still being protected against ++ pathological inputs. ++ + @type strio: file + @param strio: Bytes will be read from this file until the full Name +- is decoded. ++ is decoded. ++ ++ @type length: L{int} or L{None} ++ @param length: Present for compatibility with the L{IEncodable} ++ interface; ignored by this decoder. + + @raise EOFError: Raised when there are not enough bytes available +- from C{strio}. ++ from C{strio}. ++ ++ @raise ValueError: Raised when the name cannot be decoded because ++ it contains a compression loop. + +- @raise ValueError: Raised when the name cannot be decoded (for example, +- because it contains a loop). ++ @raise DNSDecodeError: Raised when the cumulative number of ++ compression-pointer jumps exceeds the configured limit. + """ ++ context = _decodeContextVar.get() ++ if context is None: ++ context = _DecodeContext(maxJumps=self.maxCompressionPointers) + visited = set() + self.name = b"" + off = 0 +@@ -616,6 +726,7 @@ class Name: + return + if (l >> 6) == 3: + new_off = (l & 63) << 8 | ord(readPrecisely(strio, 1)) ++ context.registerJump() + if new_off in visited: + raise ValueError("Compression loop in encoded name") + visited.add(new_off) +@@ -2488,8 +2599,17 @@ class Message(tputil.FancyEqMixin): + header fields. + @ivar _sectionNames: The names of attributes representing the record + sections of this message. ++ ++ @ivar maxCompressionPointers: Per-message cap on the total number of ++ compression-pointer dereferences L{decode} will follow across every ++ name in the message before raising L{DNSDecodeError}. Defaults to ++ C{1000}. Override it on a subclass or individual instance to tune ++ the trade-off between tolerance for legitimately verbose messages ++ and resistance to denial-of-service attacks. + """ + ++ maxCompressionPointers: int = 1000 ++ + compareAttributes = ( + "id", + "answer", +@@ -2704,19 +2824,29 @@ class Message(tputil.FancyEqMixin): + self.checkingDisabled = (byte4 >> 4) & 1 + self.rCode = byte4 & 0xF + +- self.queries = [] +- for i in range(nqueries): +- q = Query() +- try: +- q.decode(strio) +- except EOFError: +- return +- self.queries.append(q) ++ # A single shared counter bounds the total compression-pointer work ++ # performed across every name in this message. It is installed on ++ # the private context variable so nested record decoders pick it up ++ # without needing to thread it through each signature. ++ decodeContext = _DecodeContext(maxJumps=self.maxCompressionPointers) ++ with _installDecodeContext(decodeContext): ++ self.queries = [] ++ for i in range(nqueries): ++ q = Query() ++ try: ++ q.decode(strio) ++ except EOFError: ++ return ++ self.queries.append(q) + +- items = ((self.answers, nans), (self.authority, nns), (self.additional, nadd)) ++ items = ( ++ (self.answers, nans), ++ (self.authority, nns), ++ (self.additional, nadd), ++ ) + +- for l, n in items: +- self.parseRecords(l, n, strio) ++ for l, n in items: ++ self.parseRecords(l, n, strio) + + def parseRecords(self, list, num, strio): + for i in range(num): +diff --git a/src/twisted/names/test/test_dns.py b/src/twisted/names/test/test_dns.py +index 3b8f6e130..3be6b4546 100644 +--- a/src/twisted/names/test/test_dns.py ++++ b/src/twisted/names/test/test_dns.py +@@ -352,6 +352,54 @@ class NameTests(unittest.TestCase): + stream = BytesIO(b"\xc0\x00") + self.assertRaises(ValueError, name.decode, stream) + ++ def test_rejectTooManyCompressionPointers(self): ++ """ ++ L{Name.decode} raises L{dns.DNSDecodeError} when it would have to ++ follow more than L{Name.maxCompressionPointers} compression ++ pointers to finish decoding a name. ++ """ ++ # Four distinct pointers chained end-to-end, terminated by a zero ++ # label byte. With maxCompressionPointers of three the fourth ++ # dereference must trip the safety limit. ++ payload = b"\xc0\x02\xc0\x04\xc0\x06\xc0\x08\x00" ++ name = dns.Name() ++ name.maxCompressionPointers = 3 ++ self.assertRaises( ++ dns.DNSDecodeError, name.decode, BytesIO(payload) ++ ) ++ ++ def test_decodeRecoversAfterDNSDecodeError(self): ++ """ ++ After L{Name.decode} raises L{dns.DNSDecodeError}, subsequent ++ L{Name.decode} calls continue to work. No residual ++ compression-pointer counter leaks across calls, so a legitimate ++ name decoded right after a hostile one still succeeds. ++ """ ++ # First, force a DNSDecodeError by decoding a payload that ++ # exceeds the configured limit. ++ hostile = dns.Name() ++ hostile.maxCompressionPointers = 3 ++ self.assertRaises( ++ dns.DNSDecodeError, ++ hostile.decode, ++ BytesIO(b"\xc0\x02\xc0\x04\xc0\x06\xc0\x08\x00"), ++ ) ++ ++ # Then prove the process has not been poisoned: a legitimate ++ # name still decodes normally, both with a fresh instance and ++ # with the instance that just errored. ++ stream = BytesIO() ++ dns.Name(b"example.org").encode(stream) ++ ++ fresh = dns.Name() ++ stream.seek(0) ++ fresh.decode(stream) ++ self.assertEqual(fresh.name, b"example.org") ++ ++ stream.seek(0) ++ hostile.decode(stream) ++ self.assertEqual(hostile.name, b"example.org") ++ + def test_equality(self): + """ + L{Name} instances are equal as long as they have the same value for +@@ -761,6 +809,43 @@ class MessageTests(unittest.SynchronousTestCase): + """ + self.assertEqual(dns.Message().authenticData, 0) + ++ def test_rejectCompressionPointerFlood(self): ++ """ ++ L{Message.decode} installs a shared compression-pointer counter and ++ raises L{dns.DNSDecodeError} when the aggregate number of pointer ++ dereferences across every record in the message exceeds ++ L{dns.Message.maxCompressionPointers}. ++ """ ++ chainLength = 100 ++ numRecords = 8000 ++ header = struct.pack( ++ "!H2B4H", 0x1234, 0x80, 0x00, 0, numRecords, 0, 0 ++ ) ++ ++ # Long compression chain inside the RDATA of an unknown ++ # record so that subsequent records can aim pointers at it. ++ owner = b"\x04rrrr\x00" ++ chainBase = len(header) + len(owner) + 10 ++ chain = bytearray() ++ for i in range(chainLength): ++ chain += struct.pack("!H", 0xC000 | (chainBase + 2 * (i + 1))) ++ chain += b"\x04test\x00" ++ ++ firstRecord = ( ++ owner ++ + struct.pack("!HHIH", 999, 1, 0, len(chain)) ++ + bytes(chain) ++ ) ++ followupRecord = ( ++ struct.pack("!H", 0xC000 | chainBase) ++ + struct.pack("!HHIH", 1, 1, 0, 4) ++ + b"\x00\x00\x00\x00" ++ ) ++ payload = header + firstRecord + followupRecord * (numRecords - 1) ++ ++ message = dns.Message() ++ self.assertRaises(dns.DNSDecodeError, message.decode, BytesIO(payload)) ++ + def test_authenticDataOverride(self): + """ + L{dns.Message.__init__} accepts a C{authenticData} argument which diff --git a/meta-python/recipes-devtools/python/python3-twisted_24.3.0.bb b/meta-python/recipes-devtools/python/python3-twisted_24.3.0.bb index 691b80ac68..59aef8a606 100644 --- a/meta-python/recipes-devtools/python/python3-twisted_24.3.0.bb +++ b/meta-python/recipes-devtools/python/python3-twisted_24.3.0.bb @@ -9,6 +9,7 @@ LIC_FILES_CHKSUM = "file://LICENSE;md5=c1c5d2c2493b848f83864bdedd67bbf5" SRC_URI += " \ file://CVE-2024-41671.patch \ file://CVE-2024-41810.patch \ + file://CVE-2026-42304.patch \ " SRC_URI[sha256sum] = "6b38b6ece7296b5e122c9eb17da2eeab3d98a198f50ca9efd00fb03e5b4fd4ae" @@ -178,4 +179,3 @@ FILES:${PN}-pair = " \ FILES:${PN}-doc += " \ ${PYTHON_SITEPACKAGES_DIR}/twisted/python/_pydoctortemplates \ " -