Open
reject unsupported b64 critical header extension and Fix CVE-2026-48526 #49
reject unsupported b64 critical header extension and Fix CVE-2026-48526 #49
Open
lipengyu001Add on Jul 21
Total: 3 files changed+158-2
@@ -0,0 +1,54 @@
1+From 7a4b857508963c6d3953fd8e59c3c2e1d52b2915 Mon Sep 17 00:00:00 2001
2+From: OpenEuler Security Team <security@openeuler.org>
3+Date: Tue, 21 Jul 2026 12:00:00 +0800
4+Subject: [PATCH] CVE-2026-32597: do not advertise unsupported b64 critical
5+ extension
6+ 
7+PyJWT 2.3.0 does not implement RFC 7797's b64=false processing. The
8+initial backport marked b64 as supported nevertheless, allowing a token
9+with crit=["b64"] to pass critical-header validation without interpreting
10+the extension. Reject it like every other unsupported critical extension.
11+ 
12+---
13+ jwt/api_jws.py | 4 +++-
14+ tests/test_api_jws.py | 17 +++++++++++++++++
15+ 2 files changed, 20 insertions(+), 1 deletion(-)
16+ 
17+diff --git a/jwt/api_jws.py b/jwt/api_jws.py
18+index d53f0f0..89c45c1 100644
19+--- a/jwt/api_jws.py
20++++ b/jwt/api_jws.py
21+@@ -246,6 +246,8 @@ class PyJWS:
22+
23+ # Extensions that PyJWT actually understands and supports
24+- _supported_crit = {"b64"}
25++ #
26++ # PyJWT 2.3.0 does not implement any JWS critical extensions.
27++ _supported_crit = set()
28+
29+ def _validate_headers(self, headers, *, encoding=False):
30+ if "kid" in headers:
31+diff --git a/tests/test_api_jws.py b/tests/test_api_jws.py
32+index 2a2256f..780d6e6 100644
33+--- a/tests/test_api_jws.py
34++++ b/tests/test_api_jws.py
35+@@ -721,0 +722,17 @@ class TestJWS:
36++ def test_decode_rejects_unsupported_b64_crit_extension(self, jws, payload):
37++ token = jws.encode(
38++ payload,
39++ "secret",
40++ algorithm="HS256",
41++ headers={"crit": ["b64"], "b64": False},
42++ )
43++
44++ with pytest.raises(
45++ InvalidTokenError, match="Unsupported critical extension: b64"
46++ ):
47++ jws.decode(token, "secret", algorithms=["HS256"])
48++
49++ with pytest.raises(
50++ InvalidTokenError, match="Unsupported critical extension: b64"
51++ ):
52++ jws.get_unverified_header(token)
53+--
54+ 2.39.5
@@ -0,0 +1,94 @@
1+From 3bb266d5342aa65e67bed0ed9e979b5a51b23bb5 Mon Sep 17 00:00:00 2001
2+From: OpenEuler Security Team <security@openeuler.org>
3+Date: Tue, 21 Jul 2026 12:00:00 +0800
4+Subject: [PATCH] CVE-2026-48526: reject raw JWKs as HMAC secrets
5+ 
6+Raw JSON Web Keys must be parsed with HMACAlgorithm.from_jwk(), rather
7+than used as arbitrary HMAC secret bytes. This blocks algorithm-confusion
8+attacks when a verifier incorrectly permits both HMAC and asymmetric
9+algorithms and provides a public JWK as its key.
10+ 
11+---
12+ jwt/algorithms.py | 17 +++++++++++++++++
13+ tests/test_api_jws.py | 20 ++++++++++++++++++++
14+ 2 files changed, 37 insertions(+), 1 deletion(-)
15+ 
16+diff --git a/jwt/algorithms.py b/jwt/algorithms.py
17+index 1aa30ed..7420d2f 100644
18+--- a/jwt/algorithms.py
19++++ b/jwt/algorithms.py
20+@@ -186,6 +186,23 @@ class HMACAlgorithm(Algorithm):
21+ " should not be used as an HMAC secret."
22+ )
23+
24++ # A raw JWK is public key metadata, not the HMAC secret material.
25++ # Requiring callers to use from_jwk() prevents an attacker from
26++ # switching a mixed algorithm allow-list to HS* and using an issuer's
27++ # public JWK as the HMAC key.
28++ if key.lstrip().startswith(b"{"):
29++ try:
30++ jwk = json.loads(key)
31++ except ValueError:
32++ jwk = None
33++
34++ if isinstance(jwk, dict) and "kty" in jwk:
35++ raise InvalidKeyError(
36++ "The specified key looks like a JWK and should not be "
37++ "used directly as an HMAC secret. Load it via "
38++ "HMACAlgorithm.from_jwk first."
39++ )
40++
41+ return key
42+
43+ @staticmethod
44+diff --git a/tests/test_api_jws.py b/tests/test_api_jws.py
45+index 780d6e6..a40b97b 100644
46+--- a/tests/test_api_jws.py
47++++ b/tests/test_api_jws.py
48+@@ -1,18 +1,21 @@
49++import hashlib
50++import hmac
51+ import json
52+ from decimal import Decimal
53+
54+ import pytest
55+
56+ from jwt.algorithms import Algorithm, has_crypto
57+ from jwt.api_jws import PyJWS
58+ from jwt.exceptions import (
59+ DecodeError,
60+ InvalidAlgorithmError,
61++ InvalidKeyError,
62+ InvalidSignatureError,
63+ InvalidTokenError,
64+ )
65+-from jwt.utils import base64url_decode
66++from jwt.utils import base64url_decode, base64url_encode
67+
68+ from .utils import crypto_required, key_path, no_crypto_required
69+
70+ try:
71+@@ -571,4 +574,20 @@ class TestJWS:
72+ with pytest.raises(
73+ InvalidTokenError, match="Unsupported critical extension: b64"
74+ ):
75+ jws.get_unverified_header(token)
76++
77++ def test_decode_rejects_jwk_used_as_hmac_secret(self, jws, payload):
78++ public_jwk = '{"kty":"RSA","n":"AQAB","e":"AQAB"}'
79++ header = base64url_encode(b'{"alg":"HS256","typ":"JWT"}')
80++ signing_input = b".".join((header, base64url_encode(payload)))
81++ signature = hmac.new(
82++ public_jwk.encode("utf-8"), signing_input, hashlib.sha256
83++ ).digest()
84++ token = b".".join((signing_input, base64url_encode(signature))).decode(
85++ "ascii"
86++ )
87++
88++ with pytest.raises(
89++ InvalidKeyError, match="should not be used directly as an HMAC secret"
90++ ):
91++ jws.decode(token, public_jwk, algorithms=["HS256", "RS256"])
92+ 
93+--
94+2.39.5
@@ -2,7 +2,7 @@
2%bcond_without tests2%bcond_without tests
3Name: python-jwt3Name: python-jwt
4Version: 2.3.04Version: 2.3.0
5-Release: 55+Release: 6
6Summary: JSON Web Token implementation in Python6Summary: JSON Web Token implementation in Python
7License: MIT7License: MIT
8URL: https://github.com/jpadilla/pyjwt8URL: https://github.com/jpadilla/pyjwt
@@ -12,7 +12,9 @@ BuildArch: noarch
12Patch6000: backport-CVE-2022-29217.patch12Patch6000: backport-CVE-2022-29217.patch
13Patch6001: backport-fix-failing-advisory-test.patch13Patch6001: backport-fix-failing-advisory-test.patch
14Patch6002: backport-chore-fix-lint-errors.patch14Patch6002: backport-chore-fix-lint-errors.patch
15-Patch6003: backport-CVE-2026-32597-1.patch15+Patch6003: backport-CVE-2026-32597-1.patch
16+Patch6004: backport-CVE-2026-32597-2.patch
17+Patch6005: backport-CVE-2026-48526.patch
16 18 
17%if %{with tests}19%if %{with tests}
18BuildRequires: python3-pytest python3-pytest-cov python3-pytest-runner20BuildRequires: python3-pytest python3-pytest-cov python3-pytest-runner
@@ -58,6 +60,12 @@ Requires: python%{python3_pkgversion}-cryptography
58%doc README.rst60%doc README.rst
59 61 
60%changelog62%changelog
63+* Tue Jul 21 2026 lipengyu <lipengyu@kylinos.cn> - 2.3.0-6
64+- Type:CVE
65+- CVE:CVE-2026-32597 CVE-2026-48526
66+- DESC:reject unsupported b64 critical header extension
67+ Fix CVE-2026-48526
68+ 
61* Fri Jul 17 2026 xiaoo_robot <xiaoo_robot@petalmail.com> - 2.3.0-569* Fri Jul 17 2026 xiaoo_robot <xiaoo_robot@petalmail.com> - 2.3.0-5
62- Type:CVE70- Type:CVE
63- CVE:CVE-2026-3259771- CVE:CVE-2026-32597