diff mbox series

[meta-python,scarthgap,3/5] python3-pyjwt: Fix CVE-2026-48525

Message ID 20260806055101.23160-3-hthakar@cisco.com
State New
Headers show
Series [meta-python,scarthgap,1/5] python3-pyjwt: Fix CVE-2026-48522 | expand

Commit Message

From: Hetvi Thakar <hthakar@cisco.com>

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 <hthakar@cisco.com>
---
 .../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 mbox series

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?= <jpadilla@users.noreply.github.com>
+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 <hthakar@cisco.com>
+---
+ 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"