[meta-python][wrynose][PATCH 1/6] python3-pyjwt: Fix CVE-2026-48522

"Hetvi Thakar -X (hthakar - E INFOCHIPS PRIVATE LIMITED at Cisco)" <[email protected]>
Newsgroups org.openembedded.lists.openembedded-devel
Message-ID <[email protected]>
From: Hetvi Thakar <[email protected]>

This patch applies the upstream 2.13.0 backport for
CVE-2026-48522. The upstream fix commit is referenced in [1],
and the public CVE 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 <[email protected]>
---
 .../python/files/CVE-2026-48522.patch         | 126 ++++++++++++++++++
 .../python/python3-pyjwt_2.12.1.bb            |   2 +
 2 files changed, 128 insertions(+)
 create mode 100644 meta-python/recipes-devtools/python/files/CVE-2026-48522.patch

diff --git a/meta-python/recipes-devtools/python/files/CVE-2026-48522.patch b/meta-python/recipes-devtools/python/files/CVE-2026-48522.patch
new file mode 100644
index 0000000000..c1e6466d35
--- /dev/null
+++ b/meta-python/recipes-devtools/python/files/CVE-2026-48522.patch
@@ -0,0 +1,126 @@
+From f369d32169410b17717d2a9c00d5bf3ac655c85d Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Jos=C3=A9=20Padilla?= <[email protected]>
+Date: Thu, 21 May 2026 14:11:10 -0400
+Subject: [PATCH] Bundle security fixes and hardening into 2.13.0
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Security:
+- `HMACAlgorithm.prepare_key` rejects JWK JSON documents passed as raw
+  HMAC secrets to close an algorithm-confusion gap not covered by the
+  existing PEM/SSH guard. Reported by @aradona91 in GHSA-xgmm-8j9v-c9wx.
+- Bind the JWT header `alg` to `PyJWK.algorithm_name` during verification
+  so the caller's `algorithms` allow-list cannot be bypassed when decoding
+  with a `PyJWK` / `PyJWKClient` key. Reported by @sushi-gif in
+  GHSA-jq35-7prp-9v3f.
+- Skip the unconditional base64 decode of the compact-form payload
+  segment when `b64=false` is set, and require that segment to be empty
+  (RFC 7515 Appendix F detached form). Closes an unauthenticated DoS
+  amplifier. Reported by @thesmartshadow in GHSA-w7vc-732c-9m39.
+- `PyJWKClient` rejects any URI whose scheme is not `http` or `https` so
+  attacker-influenced URIs cannot read local files or reach unintended
+  schemes via urllib's default `file://` / `ftp://` / `data:` handlers.
+  Reported by @KEIJOT in GHSA-993g-76c3-p5m4.
+- Preserve the cached JWK Set on fetch errors in `PyJWKClient.fetch_data`.
+  The previous `finally`-block `put(None)` pattern cleared the cache on
+  any transient outage. Reported by @eddieran in GHSA-fhv5-28vv-h8m8.
+
+Fixes:
+- Reject empty HMAC keys outright in `HMACAlgorithm.prepare_key` with
+  `InvalidKeyError` instead of accepting them with only a warning.
+  Hardening prompted by reports from @SnailSploit and @spartan8806.
+- Forward per-call `options` (including `enforce_minimum_key_length`)
+  from `PyJWT.decode` through to `PyJWS._verify_signature`. Thanks to
+  @WLUB.
+- RFC 7797 §3 compliance for `b64=false`: encoder auto-adds `"b64"` to
+  `crit`; decoder rejects tokens that set `b64=false` without listing
+  it in `crit`. Thanks to @MachineLearning-Nerd.
+
+CVE: CVE-2026-48522
+Upstream-Status: Backport [https://github.com/jpadilla/pyjwt/commit/95791b1759b8aa4f2203575d344d5c78564cdc81]
+
+Backport Changes:
+- Split out the PyJWKClient URI-scheme validation because the upstream
+  commit bundles multiple CVEs.
+- Omitted CHANGELOG.rst because it conflicted and is release documentation.
+- Omitted the 2.13.0 version bump and other bundled fixes; applicable CVE
+  fixes are carried in separate patches.
+
+(cherry picked from commit 95791b1759b8aa4f2203575d344d5c78564cdc81)
+Signed-off-by: Hetvi Thakar <[email protected]>
+---
+ jwt/jwks_client.py        | 11 +++++++++++
+ tests/test_jwks_client.py | 30 ++++++++++++++++++++++++++++++
+ 2 files changed, 41 insertions(+)
+
+diff --git a/jwt/jwks_client.py b/jwt/jwks_client.py
+index b81e8f4..8d1b0c4 100644
+--- a/jwt/jwks_client.py
++++ b/jwt/jwks_client.py
+@@ -6,6 +6,7 @@ from functools import lru_cache
+ from ssl import SSLContext
+ from typing import Any
+ from urllib.error import HTTPError, URLError
++from urllib.parse import urlparse
+ 
+ from .api_jwk import PyJWK, PyJWKSet
+ from .api_jwt import decode_complete as decode_token
+@@ -69,6 +70,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: JWKSetCache | None = None
+         self.headers = headers
+diff --git a/tests/test_jwks_client.py b/tests/test_jwks_client.py
+index ceee672..d6793cc 100644
+--- a/tests/test_jwks_client.py
++++ b/tests/test_jwks_client.py
+@@ -344,6 +344,36 @@ 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",  # urlparse gives scheme="" — also rejected
++            "ldap://internal.test/jwks",
++        ],
++    )
++    def test_pyjwkclient_rejects_non_http_schemes(self, uri: str) -> None:
++        # urllib's default OpenerDirector handles file://, ftp://, and data:
++        # URIs. PyJWKClient must reject these so callers can't be tricked
++        # into reading attacker-controlled local files or other unintended
++        # schemes via a manipulated URI.
++        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",  # case-insensitive
++        ],
++    )
++    def test_pyjwkclient_accepts_http_https_schemes(self, uri: str) -> None:
++        # Construction succeeds; no fetch is made until get_jwk_set().
++        PyJWKClient(uri)
++
+     def test_get_jwt_set_timeout(self) -> None:
+         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.12.1.bb b/meta-python/recipes-devtools/python/python3-pyjwt_2.12.1.bb
index eb445f9c91..ed7a280ee5 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
@@ -5,6 +5,8 @@ HOMEPAGE = "https://github.com/jpadilla/pyjwt"
 LICENSE = "MIT"
 LIC_FILES_CHKSUM = "file://LICENSE;md5=e4b56d2c9973d8cf54655555be06e551"
 
+SRC_URI += "file://CVE-2026-48522.patch"
+
 SRC_URI[sha256sum] = "c74a7a2adf861c04d002db713dd85f84beb242228e671280bf709d765b03672b"
 
 PYPI_PACKAGE = "pyjwt"
-- 
2.35.6
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.