new file mode 100644
@@ -0,0 +1,115 @@
+From 6590add3a8d18098b107fe446ff256ae92e7238f Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Jos=C3=A9=20Padilla?= <jpadilla@users.noreply.github.com>
+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-48523
+Upstream-Status: Backport [https://github.com/jpadilla/pyjwt/commit/95791b1759b8aa4f2203575d344d5c78564cdc81]
+
+Backport Changes:
+- Split out the PyJWK algorithm-binding 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 <hthakar@cisco.com>
+---
+ jwt/api_jws.py | 10 ++++++++++
+ tests/test_api_jws.py | 27 +++++++++++++++++++++++++++
+ 2 files changed, 37 insertions(+)
+
+diff --git a/jwt/api_jws.py b/jwt/api_jws.py
+index 0ab7e4b..91d2ae3 100644
+--- a/jwt/api_jws.py
++++ b/jwt/api_jws.py
+@@ -348,6 +348,16 @@ class PyJWS:
+ raise InvalidAlgorithmError("The specified alg value is not allowed")
+
+ if isinstance(key, PyJWK):
++ # The PyJWK has a fixed algorithm bound at construction time.
++ # Verification must use that algorithm, not whatever the token
++ # header advertises, otherwise the caller's allow-list check
++ # above degenerates into a string compare with no behavioural
++ # effect on which algorithm actually verifies the signature.
++ if alg != key.algorithm_name:
++ raise InvalidAlgorithmError(
++ f"Token algorithm {alg!r} does not match the key's "
++ f"algorithm {key.algorithm_name!r}"
++ )
+ alg_obj = key.Algorithm
+ prepared_key = key.key
+ else:
+diff --git a/tests/test_api_jws.py b/tests/test_api_jws.py
+index 9f7edc0..0715b9e 100644
+--- a/tests/test_api_jws.py
++++ b/tests/test_api_jws.py
+@@ -397,6 +397,33 @@ class TestJWS:
+ with pytest.raises(InvalidAlgorithmError):
+ jws.decode(example_jws, jwk)
+
++ def test_decodes_with_jwk_rejects_header_alg_outside_jwk_alg(
++ self, jws: PyJWS
++ ) -> None:
++ # Token header says HS256 and the caller's allow-list also accepts
++ # HS256, but the PyJWK is bound to HS512. Even though the allow-list
++ # would pass, verification must be locked to the PyJWK's algorithm
++ # rather than the header's — otherwise an attacker who controls a
++ # registered key can advertise a disallowed algorithm in the header
++ # and have it accepted.
++ jwk = PyJWK(
++ {
++ "kty": "oct",
++ "alg": "HS512",
++ "k": "c2VjcmV0", # "secret"
++ }
++ )
++ example_jws = (
++ b"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9."
++ b"aGVsbG8gd29ybGQ."
++ b"gEW0pdU4kxPthjtehYdhxB9mMOGajt1xCKlGGXDJ8PM"
++ )
++
++ with pytest.raises(
++ InvalidAlgorithmError, match="does not match the key's algorithm"
++ ):
++ jws.decode(example_jws, jwk, algorithms=["HS256", "HS512"])
++
+ # 'Control' Elliptic Curve jws created by another library.
+ # Used to test for regressions that could affect both
+ # encoding / decoding operations equally (causing tests
@@ -5,7 +5,9 @@ HOMEPAGE = "https://github.com/jpadilla/pyjwt"
LICENSE = "MIT"
LIC_FILES_CHKSUM = "file://LICENSE;md5=e4b56d2c9973d8cf54655555be06e551"
-SRC_URI += "file://CVE-2026-48522.patch"
+SRC_URI += "file://CVE-2026-48522.patch \
+ file://CVE-2026-48523.patch \
+ "
SRC_URI[sha256sum] = "c74a7a2adf861c04d002db713dd85f84beb242228e671280bf709d765b03672b"