mirror of
https://github.com/openembedded/meta-openembedded.git
synced 2026-11-13 03:37:15 +00:00
python3-pyjwt: fix CVE-2026-102269
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 <hthakar@cisco.com> Signed-off-by: Anuj Mittal <anuj.mittal@oss.qualcomm.com>
This commit is contained in:
1 parent
e93a40cd9d
commit
fb76c963d9
2 files changed
+134
No files matched your search
@@ -0,0 +1,133 @@
|
||||
From e6f48401001609a8f99e71fcaf355fb895d508a8 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Jos=C3=A9=20Padilla?= <jpadilla@users.noreply.github.com>
|
||||
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 <hthakar@cisco.com>
|
||||
---
|
||||
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
|
||||
@@ -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"
|
||||
|
||||
Reference in new issue
Block a user