Skip to content

[CU-86b4umhm1] Update dependency pyjwt to v2.13.0 [SECURITY]#159

Open
dnastack-renovate[bot] wants to merge 1 commit into
mainfrom
renovate/pypi-pyjwt-vulnerability
Open

[CU-86b4umhm1] Update dependency pyjwt to v2.13.0 [SECURITY]#159
dnastack-renovate[bot] wants to merge 1 commit into
mainfrom
renovate/pypi-pyjwt-vulnerability

Conversation

@dnastack-renovate
Copy link
Copy Markdown
Contributor

@dnastack-renovate dnastack-renovate Bot commented Mar 14, 2026

Note: This PR body was truncated due to platform limits.

This PR contains the following updates:

Package Change Age Adoption Passing Confidence
pyjwt 2.10.12.13.0 age adoption passing confidence

GitHub Vulnerability Alerts

CVE-2026-32597

Summary

PyJWT does not validate the crit (Critical) Header Parameter defined in
RFC 7515 §4.1.11. When a JWS token contains a crit array listing
extensions that PyJWT does not understand, the library accepts the token
instead of rejecting it. This violates the MUST requirement in the RFC.

This is the same class of vulnerability as CVE-2025-59420 (Authlib),
which received CVSS 7.5 (HIGH).


RFC Requirement

RFC 7515 §4.1.11:

The "crit" (Critical) Header Parameter indicates that extensions to this
specification and/or [JWA] are being used that MUST be understood and
processed. [...] If any of the listed extension Header Parameters are
not understood and supported by the recipient, then the JWS is invalid.


Proof of Concept

import jwt  # PyJWT 2.8.0
import hmac, hashlib, base64, json

# Construct token with unknown critical extension
header = {"alg": "HS256", "crit": ["x-custom-policy"], "x-custom-policy": "require-mfa"}
payload = {"sub": "attacker", "role": "admin"}

def b64url(data):
    return base64.urlsafe_b64encode(data).rstrip(b"=").decode()

h = b64url(json.dumps(header, separators=(",", ":")).encode())
p = b64url(json.dumps(payload, separators=(",", ":")).encode())
sig = b64url(hmac.new(b"secret", f"{h}.{p}".encode(), hashlib.sha256).digest())
token = f"{h}.{p}.{sig}"

# Should REJECT — x-custom-policy is not understood by PyJWT
try:
    result = jwt.decode(token, "secret", algorithms=["HS256"])
    print(f"ACCEPTED: {result}")
    # Output: ACCEPTED: {'sub': 'attacker', 'role': 'admin'}
except Exception as e:
    print(f"REJECTED: {e}")

Expected: jwt.exceptions.InvalidTokenError: Unsupported critical extension: x-custom-policy
Actual: Token accepted, payload returned.

Comparison with RFC-compliant library

# jwcrypto — correctly rejects
from jwcrypto import jwt as jw_jwt, jwk
key = jwk.JWK(kty="oct", k=b64url(b"secret"))
jw_jwt.JWT(jwt=token, key=key, algs=["HS256"])

# raises: InvalidJWSObject('Unknown critical header: "x-custom-policy"')

Impact

  • Split-brain verification in mixed-library deployments (e.g., API
    gateway using jwcrypto rejects, backend using PyJWT accepts)
  • Security policy bypass when crit carries enforcement semantics
    (MFA, token binding, scope restrictions)
  • Token binding bypass — RFC 7800 cnf (Proof-of-Possession) can be
    silently ignored
  • See CVE-2025-59420 for full impact analysis

Suggested Fix

In jwt/api_jwt.py, add validation in _validate_headers() or
decode():

_SUPPORTED_CRIT = {"b64"}  # Add extensions PyJWT actually supports

def _validate_crit(self, headers: dict) -> None:
    crit = headers.get("crit")
    if crit is None:
        return
    if not isinstance(crit, list) or len(crit) == 0:
        raise InvalidTokenError("crit must be a non-empty array")
    for ext in crit:
        if ext not in self._SUPPORTED_CRIT:
            raise InvalidTokenError(f"Unsupported critical extension: {ext}")
        if ext not in headers:
            raise InvalidTokenError(f"Critical extension {ext} not in header")

CWE

  • CWE-345: Insufficient Verification of Data Authenticity
  • CWE-863: Incorrect Authorization

References


CVE-2025-45768 / PYSEC-2025-183

More information

Details

pyjwt v2.10.1 was discovered to contain weak encryption. NOTE: this is disputed by the Supplier because the key length is chosen by the application that uses the library (admittedly, library users may benefit from a minimum value and a mechanism for opting in to strict enforcement).

Severity

  • CVSS Score: 7.0 / 10 (High)
  • Vector String: CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:H

References

This data is provided by OSV and the PyPI Advisory Database (CC-BY 4.0).


CVE-2026-32597 / GHSA-752w-5fwx-jx9f / PYSEC-2026-120

More information

Details

PyJWT is a JSON Web Token implementation in Python. Prior to 2.12.0, PyJWT does not validate the crit (Critical) Header Parameter defined in RFC 7515 §4.1.11. When a JWS token contains a crit array listing extensions that PyJWT does not understand, the library accepts the token instead of rejecting it. This violates the MUST requirement in the RFC. This vulnerability is fixed in 2.12.0.

Severity

  • CVSS Score: 7.5 / 10 (High)
  • Vector String: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N

References

This data is provided by OSV and the PyPI Advisory Database (CC-BY 4.0).


PyJWT accepts unknown crit header extensions

CVE-2026-32597 / GHSA-752w-5fwx-jx9f / PYSEC-2026-120

More information

Details

Summary

PyJWT does not validate the crit (Critical) Header Parameter defined in
RFC 7515 §4.1.11. When a JWS token contains a crit array listing
extensions that PyJWT does not understand, the library accepts the token
instead of rejecting it. This violates the MUST requirement in the RFC.

This is the same class of vulnerability as CVE-2025-59420 (Authlib),
which received CVSS 7.5 (HIGH).


RFC Requirement

RFC 7515 §4.1.11:

The "crit" (Critical) Header Parameter indicates that extensions to this
specification and/or [JWA] are being used that MUST be understood and
processed. [...] If any of the listed extension Header Parameters are
not understood and supported by the recipient, then the JWS is invalid.


Proof of Concept
import jwt  # PyJWT 2.8.0
import hmac, hashlib, base64, json

##### Construct token with unknown critical extension
header = {"alg": "HS256", "crit": ["x-custom-policy"], "x-custom-policy": "require-mfa"}
payload = {"sub": "attacker", "role": "admin"}

def b64url(data):
    return base64.urlsafe_b64encode(data).rstrip(b"=").decode()

h = b64url(json.dumps(header, separators=(",", ":")).encode())
p = b64url(json.dumps(payload, separators=(",", ":")).encode())
sig = b64url(hmac.new(b"secret", f"{h}.{p}".encode(), hashlib.sha256).digest())
token = f"{h}.{p}.{sig}"

##### Should REJECT — x-custom-policy is not understood by PyJWT
try:
    result = jwt.decode(token, "secret", algorithms=["HS256"])
    print(f"ACCEPTED: {result}")
    # Output: ACCEPTED: {'sub': 'attacker', 'role': 'admin'}
except Exception as e:
    print(f"REJECTED: {e}")

Expected: jwt.exceptions.InvalidTokenError: Unsupported critical extension: x-custom-policy
Actual: Token accepted, payload returned.

Comparison with RFC-compliant library
##### jwcrypto — correctly rejects
from jwcrypto import jwt as jw_jwt, jwk
key = jwk.JWK(kty="oct", k=b64url(b"secret"))
jw_jwt.JWT(jwt=token, key=key, algs=["HS256"])

##### raises: InvalidJWSObject('Unknown critical header: "x-custom-policy"')

Impact
  • Split-brain verification in mixed-library deployments (e.g., API
    gateway using jwcrypto rejects, backend using PyJWT accepts)
  • Security policy bypass when crit carries enforcement semantics
    (MFA, token binding, scope restrictions)
  • Token binding bypass — RFC 7800 cnf (Proof-of-Possession) can be
    silently ignored
  • See CVE-2025-59420 for full impact analysis

Suggested Fix

In jwt/api_jwt.py, add validation in _validate_headers() or
decode():

_SUPPORTED_CRIT = {"b64"}  # Add extensions PyJWT actually supports

def _validate_crit(self, headers: dict) -> None:
    crit = headers.get("crit")
    if crit is None:
        return
    if not isinstance(crit, list) or len(crit) == 0:
        raise InvalidTokenError("crit must be a non-empty array")
    for ext in crit:
        if ext not in self._SUPPORTED_CRIT:
            raise InvalidTokenError(f"Unsupported critical extension: {ext}")
        if ext not in headers:
            raise InvalidTokenError(f"Critical extension {ext} not in header")

CWE
  • CWE-345: Insufficient Verification of Data Authenticity
  • CWE-863: Incorrect Authorization
References

Severity

  • CVSS Score: 7.5 / 10 (High)
  • Vector String: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N

References

This data is provided by OSV and the GitHub Advisory Database (CC-BY 4.0).


CVE-2026-48523 / GHSA-jq35-7prp-9v3f / PYSEC-2026-176

More information

Details

PyJWT is a JSON Web Token implementation in Python. From 2.9.0 to 2.12.1, there is a verifier-side algorithm allow-list bypass when jwt.decode() or jwt.decode_complete() are called with a PyJWK key. The token header alg is checked against the caller-supplied algorithms allow-list, but signature verification is performed with the algorithm bound to the PyJWK object instead of the header algorithm. An attacker who controls a registered JWK/JWKS private key can sign with a disallowed algorithm, advertise an allowed algorithm in the JWT header, and still be accepted. The issue affects the documented PyJWKClient.get_signing_key_from_jwt(...) flow. This vulnerability is fixed in 2.13.0.

Severity

  • CVSS Score: 5.4 / 10 (Medium)
  • Vector String: CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:L/A:N

References

This data is provided by OSV and the PyPI Advisory Database (CC-BY 4.0).


CVE-2026-48524 / GHSA-fhv5-28vv-h8m8 / PYSEC-2026-177

More information

Details

PyJWT is a JSON Web Token implementation in Python. Prior to 2.13.0, PyJWKClient.get_signing_key() forces a fresh HTTP request to the JWKS endpoint for every JWT with an unknown kid value, with no rate limiting. Since kid comes from the unverified token header, an attacker can trigger unlimited outbound requests. The vulnerability surfaces only when a JWKS fetch fails; an attacker can attempt to provoke that with sustained unknown-kid traffic, but the outcome depends on upstream JWKS-endpoint behavior (rate limiting, transient errors) which is beyond the attacker's control. This vulnerability is fixed in 2.13.0.

Severity

  • CVSS Score: 3.7 / 10 (Low)
  • Vector String: CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:N/A:L

References

This data is provided by OSV and the PyPI Advisory Database (CC-BY 4.0).


CVE-2026-48526 / GHSA-xgmm-8j9v-c9wx / PYSEC-2026-179

More information

Details

PyJWT is a JSON Web Token implementation in Python. Prior to 2.13.0, when the verifier is decoding JSON Web Tokens, while supporting both asymmetric and HMAC algorithms, the library does not validate use of JSON Web Keys in HMAC algorithm, allowing attacker to use the issuer public key as the secret key for HMAC algorithm. This vulnerability is fixed in 2.13.0.

Severity

  • CVSS Score: 7.4 / 10 (High)
  • Vector String: CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:N

References

This data is provided by OSV and the PyPI Advisory Database (CC-BY 4.0).


CVE-2026-48525 / GHSA-w7vc-732c-9m39 / PYSEC-2026-178

More information

Details

PyJWT is a JSON Web Token implementation in Python. From 2.8.0 to 2.12.1, when verifying detached JWS tokens using the unencoded-payload option ("b64": false, RFC 7797), PyJWT performs Base64URL decoding of the compact-serialization payload segment before enforcing the detached-payload rules. For b64=false, PyJWT later discards that decoded payload and replaces it with the caller-provided detached_payload. In practice, this turns the middle segment into an attacker-controlled “work amplifier”: a remote client can supply an arbitrarily large Base64URL payload segment that forces CPU work + memory allocations even if the signature is invalid. This creates an unauthenticated DoS vector against any endpoint that verifies detached JWS using PyJWT. This vulnerability is fixed in 2.13.0.

Severity

  • CVSS Score: 5.3 / 10 (Medium)
  • Vector String: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L

References

This data is provided by OSV and the PyPI Advisory Database (CC-BY 4.0).


CVE-2026-48522 / GHSA-993g-76c3-p5m4 / PYSEC-2026-175

More information

Details

PyJWT is a JSON Web Token implementation in Python. Prior to 2.13.0, PyJWKClient passes its uri argument directly to urllib.request.urlopen() which uses Python stdlib's default OpenerDirector registering HTTPHandler, HTTPSHandler, FTPHandler, FileHandler, and DataHandler. There is currently no documented option to restrict which schemes PyJWKClient will fetch. If an application's jku URL ingestion path accepts attacker-influenced URLs (e.g., from JWT header, configuration file, OAuth flow parameter), the attacker can cause PyJWKClient to read arbitrary local files via file:// (SSRF on local filesystem), cause PyJWKClient to attempt FTP / data-URI fetches (broader SSRF surface), or forge tokens that PyJWT verifies as valid. The library does not directly return non-HTTP(S) URI contents to the attacker; the chained "plant a JWKS to forge tokens" scenario described in the original report requires additional application-layer flaws (attacker write access to a filesystem path, untrusted jku derivation) that this fix does not address. This vulnerability is fixed in 2.13.0.

Severity

  • CVSS Score: 4.2 / 10 (Medium)
  • Vector String: CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:U/C:L/I:L/A:N

References

This data is provided by OSV and the PyPI Advisory Database (CC-BY 4.0).


Release Notes

jpadilla/pyjwt (pyjwt)

v2.13.0

Compare Source

v2.12.1

Compare Source

Security


- Reject JWK JSON documents passed as raw HMAC secrets in
  ``HMACAlgorithm.prepare_key`` to close an algorithm-confusion gap that
  the existing PEM/SSH guard did not cover. Reported by @​aradona91 in
  `GHSA-xgmm-8j9v-c9wx <https://github.com/jpadilla/pyjwt/security/advisories/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 @&#8203;sushi-gif in `GHSA-jq35-7prp-9v3f <https://github.com/jpadilla/pyjwt/security/advisories/GHSA-jq35-7prp-9v3f>`__.
- Reject non-``http(s)`` URI schemes in ``PyJWKClient`` so attacker-
  influenced URIs cannot read local files or reach unintended schemes via
  urllib's default ``file://`` / ``ftp://`` / ``data:`` handlers. Reported
  by @&#8203;KEIJOT in `GHSA-993g-76c3-p5m4 <https://github.com/jpadilla/pyjwt/security/advisories/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, turning one bad JWKS request into application-
  wide auth failure. Reported by @&#8203;eddieran in `GHSA-fhv5-28vv-h8m8 <https://github.com/jpadilla/pyjwt/security/advisories/GHSA-fhv5-28vv-h8m8>`__.
- Skip the unconditional base64 decode of the compact-form payload segment
  when ``b64=false`` is set in the protected header, and require that
  segment to be empty (RFC 7515 Appendix F detached form). Closes an
  unauthenticated DoS amplifier. Reported by @&#8203;thesmartshadow in
  `GHSA-w7vc-732c-9m39 <https://github.com/jpadilla/pyjwt/security/advisories/GHSA-w7vc-732c-9m39>`__.

Fixed
~~~~~

- Reject empty HMAC keys outright in ``HMACAlgorithm.prepare_key`` with
  ``InvalidKeyError`` instead of accepting them with only a warning.
  Thanks to @&#8203;SnailSploit and @&#8203;spartan8806 for independently flagging the
  footgun.
- Forward per-call ``options`` (including ``enforce_minimum_key_length``)
  from ``PyJWT.decode`` through to ``PyJWS._verify_signature`` so the
  option actually takes effect when set at the call site rather than only
  on the ``PyJWT`` instance. Thanks to @&#8203;WLUB for the report.
- RFC 7797 §3 compliance for ``b64=false``: the encoder now auto-adds
  ``"b64"`` to the ``crit`` header parameter, and the decoder rejects
  tokens that set ``b64=false`` without listing it in ``crit``. Thanks to
  @&#8203;MachineLearning-Nerd for the report.

Changed
~~~~~~~

- Migrate the ``dev``, ``docs``, and ``tests`` package extras to dependency groups by @&#8203;kurtmckee in `#&#8203;1152 <https://github.com/jpadilla/pyjwt/pull/1152>`__

`v2.12.1 <https://github.com/jpadilla/pyjwt/compare/2.12.0...2.12.1>`__
------------------------------------------------------------------------

Fixed
~~~~~

- Add missing ``typing_extensions`` dependency for Python < 3.11 in `#&#8203;1150 <https://github.com/jpadilla/pyjwt/issues/1150>`__

`v2.12.0 <https://github.com/jpadilla/pyjwt/compare/2.11.0...2.12.0>`__
-----------------------------------------------------------------------

Fixed
~~~~~

- Annotate PyJWKSet.keys for pyright by @&#8203;tamird in `#&#8203;1134 <https://github.com/jpadilla/pyjwt/pull/1134>`__
- Close ``HTTPError`` response to prevent ``ResourceWarning`` on Python 3.14 by @&#8203;veeceey in `#&#8203;1133 <https://github.com/jpadilla/pyjwt/pull/1133>`__
- Do not keep ``algorithms`` dict in PyJWK instances by @&#8203;akx in `#&#8203;1143 <https://github.com/jpadilla/pyjwt/pull/1143>`__
- Validate the crit (Critical) Header Parameter defined in RFC 7515 §4.1.11. by @&#8203;dmbs335 in `GHSA-752w-5fwx-jx9f <https://github.com/jpadilla/pyjwt/security/advisories/GHSA-752w-5fwx-jx9f>`__
- Use PyJWK algorithm when encoding without explicit algorithm in `#&#8203;1148 <https://github.com/jpadilla/pyjwt/pull/1148>`__

Added
~~~~~

- Docs: Add ``PyJWKClient`` API reference and document the two-tier caching system (JWK Set cache and signing key LRU cache).

`v2.11.0 <https://github.com/jpadilla/pyjwt/compare/2.10.1...2.11.0>`__
-----------------------------------------------------------------------

Fixed
~~~~~

- Enforce ECDSA curve validation per RFC 7518 Section 3.4.
- Fix build system warnings by @&#8203;kurtmckee in `#&#8203;1105 <https://github.com/jpadilla/pyjwt/pull/1105>`__
- Validate key against allowed types for Algorithm family in `#&#8203;964 <https://github.com/jpadilla/pyjwt/pull/964>`__
- Add iterator for JWKSet in `#&#8203;1041 <https://github.com/jpadilla/pyjwt/pull/1041>`__
- Validate `iss` claim is a string during encoding and decoding by @&#8203;pachewise in `#&#8203;1040 <https://github.com/jpadilla/pyjwt/pull/1040>`__
- Improve typing/logic for `options` in decode, decode_complete by @&#8203;pachewise in `#&#8203;1045 <https://github.com/jpadilla/pyjwt/pull/1045>`__
- Declare float supported type for lifespan and timeout by @&#8203;nikitagashkov in `#&#8203;1068 <https://github.com/jpadilla/pyjwt/pull/1068>`__
- Fix ``SyntaxWarning``\s/``DeprecationWarning``\s caused by invalid escape sequences by @&#8203;kurtmckee in `#&#8203;1103 <https://github.com/jpadilla/pyjwt/pull/1103>`__
- Development: Build a shared wheel once to speed up test suite setup times by @&#8203;kurtmckee in `#&#8203;1114 <https://github.com/jpadilla/pyjwt/pull/1114>`__
- Development: Test type annotations across all supported Python versions,
  increase the strictness of the type checking, and remove the mypy pre-commit hook
  by @&#8203;kurtmckee in `#&#8203;1112 <https://github.com/jpadilla/pyjwt/pull/1112>`__

Added
~~~~~

- Support Python 3.14, and test against PyPy 3.10 and 3.11 by @&#8203;kurtmckee in `#&#8203;1104 <https://github.com/jpadilla/pyjwt/pull/1104>`__
- Development: Migrate to ``build`` to test package building in CI by @&#8203;kurtmckee in `#&#8203;1108 <https://github.com/jpadilla/pyjwt/pull/1108>`__
- Development: Improve coverage config and eliminate unused test suite code by @&#8203;kurtmckee in `#&#8203;1115 <https://github.com/jpadilla/pyjwt/pull/1115>`__
- Docs: Standardize CHANGELOG links to PRs by @&#8203;kurtmckee in `#&#8203;1110 <https://github.com/jpadilla/pyjwt/pull/1110>`__
- Docs: Fix Read the Docs builds by @&#8203;kurtmckee in `#&#8203;1111 <https://github.com/jpadilla/pyjwt/pull/1111>`__
- Docs: Add example of using leeway with nbf by @&#8203;djw8605 in `#&#8203;1034 <https://github.com/jpadilla/pyjwt/pull/1034>`__
- Docs: Refactored docs with ``autodoc``; added ``PyJWS`` and ``jwt.algorithms`` docs by @&#8203;pachewise in `#&#8203;1045 <https://github.com/jpadilla/pyjwt/pull/1045>`__
- Docs: Documentation improvements for "sub" and "jti" claims by @&#8203;cleder in `#&#8203;1088 <https://github.com/jpadilla/pyjwt/pull/1088>`__
- Development: Add pyupgrade as a pre-commit hook by @&#8203;kurtmckee in `#&#8203;1109 <https://github.com/jpadilla/pyjwt/pull/1109>`__
- Add minimum key length validation for HMAC and RSA keys (CWE-326).
  Warns by default via ``InsecureKeyLengthWarning`` when keys are below
  minimum recommended lengths per RFC 7518 Section 3.2 (HMAC) and
  NIST SP 800-131A (RSA). Pass ``enforce_minimum_key_length=True`` in
  options to ``PyJWT`` or ``PyJWS`` to raise ``InvalidKeyError`` instead.
- Refactor ``PyJWT`` to own an internal ``PyJWS`` instance instead of
  calling global ``api_jws`` functions.

`v2.10.1 <https://github.com/jpadilla/pyjwt/compare/2.10.0...2.10.1>`__
-----------------------------------------------------------------------

Fixed
~~~~~

- Prevent partial matching of `iss` claim by @&#8203;fabianbadoi in `GHSA-75c5-xw7c-p5pm <https://github.com/jpadilla/pyjwt/security/advisories/GHSA-75c5-xw7c-p5pm>`__

`v2.10.0 <https://github.com/jpadilla/pyjwt/compare/2.9.0...2.10.0>`__
-----------------------------------------------------------------------

Changed
~~~~~~~

- Remove algorithm requirement from JWT API, instead relying on JWS API for enforcement, by @&#8203;luhn in `#&#8203;975 <https://github.com/jpadilla/pyjwt/pull/975>`__
- Use ``Sequence`` for parameter types rather than ``List`` where applicable by @&#8203;imnotjames in `#&#8203;970 <https://github.com/jpadilla/pyjwt/pull/970>`__
- Add JWK support to JWT encode by @&#8203;luhn in `#&#8203;979 <https://github.com/jpadilla/pyjwt/pull/979>`__
- Encoding and decoding payloads using the `none` algorithm by @&#8203;jpadilla in `#c2629f6 <https://github.com/jpadilla/pyjwt/commit/c2629f66c593459e02616048443231ccbe18be16>`__

  Before:

  .. code-block:: pycon

   >>> import jwt
   >>> jwt.encode({"payload": "abc"}, key=None, algorithm=None)

  After:

  .. code-block:: pycon

   >>> import jwt
   >>> jwt.encode({"payload": "abc"}, key=None, algorithm="none")

- Added validation for 'sub' (subject) and 'jti' (JWT ID) claims in tokens by @&#8203;Divan009 in `#&#8203;1005 <https://github.com/jpadilla/pyjwt/pull/1005>`__
- Refactor project configuration files from ``setup.cfg`` to ``pyproject.toml`` by @&#8203;cleder in `#&#8203;995 <https://github.com/jpadilla/pyjwt/pull/995>`__
- Ruff linter and formatter changes by @&#8203;gagandeepp in `#&#8203;1001 <https://github.com/jpadilla/pyjwt/pull/1001>`__
- Drop support for Python 3.8 (EOL) by @&#8203;kkirsche in `#&#8203;1007 <https://github.com/jpadilla/pyjwt/pull/1007>`__

Fixed
~~~~~

- Encode EC keys with a fixed bit length by @&#8203;etianen in `#&#8203;990 <https://github.com/jpadilla/pyjwt/pull/990>`__
- Add an RTD config file to resolve Read the Docs build failures by @&#8203;kurtmckee in `#&#8203;977 <https://github.com/jpadilla/pyjwt/pull/977>`__
- Docs: Update ``iat`` exception docs by @&#8203;pachewise in `#&#8203;974 <https://github.com/jpadilla/pyjwt/pull/974>`__
- Docs: Fix ``decode_complete`` scope and algorithms by @&#8203;RbnRncn in `#&#8203;982 <https://github.com/jpadilla/pyjwt/pull/982>`__
- Fix doctest for ``docs/usage.rst`` by @&#8203;pachewise in `#&#8203;986 <https://github.com/jpadilla/pyjwt/pull/986>`__
- Fix ``test_utils.py`` not to xfail by @&#8203;pachewise in `#&#8203;987 <https://github.com/jpadilla/pyjwt/pull/987>`__
- Docs: Correct `jwt.decode` audience param doc expression by @&#8203;peter279k in `#&#8203;994 <https://github.com/jpadilla/pyjwt/pull/994>`__

Added
~~~~~

- Add support for python 3.13 by @&#8203;hugovk in `#&#8203;972 <https://github.com/jpadilla/pyjwt/pull/972>`__
- Create SECURITY.md by @&#8203;auvipy and @&#8203;jpadilla in `#&#8203;973 <https://github.com/jpadilla/pyjwt/pull/973>`__
- Docs: Add PS256 encoding and decoding usage by @&#8203;peter279k in `#&#8203;992 <https://github.com/jpadilla/pyjwt/pull/992>`__
- Docs: Add API docs for PyJWK by @&#8203;luhn in `#&#8203;980 <https://github.com/jpadilla/pyjwt/pull/980>`__
- Docs: Add EdDSA algorithm encoding/decoding usage by @&#8203;peter279k in `#&#8203;993 <https://github.com/jpadilla/pyjwt/pull/993>`__
- Include checkers and linters for ``pyproject.toml`` in ``pre-commit`` by @&#8203;cleder in `#&#8203;1002 <https://github.com/jpadilla/pyjwt/pull/1002>`__
- Docs: Add ES256 decoding usage by @&#8203;Gautam-Hegde in `#&#8203;1003 <https://github.com/jpadilla/pyjwt/pull/1003>`__

`v2.9.0 <https://github.com/jpadilla/pyjwt/compare/2.8.0...2.9.0>`__
-----------------------------------------------------------------------

Changed
~~~~~~~

- Drop support for Python 3.7 (EOL) by @&#8203;hugovk in `#&#8203;910 <https://github.com/jpadilla/pyjwt/pull/910>`__
- Allow JWT issuer claim validation to accept a list of strings too by @&#8203;mattpollak in `#&#8203;913 <https://github.com/jpadilla/pyjwt/pull/913>`__

Fixed
~~~~~

- Fix unnecessary string concatenation by @&#8203;sirosen in `#&#8203;904 <https://github.com/jpadilla/pyjwt/pull/904>`__
- Fix docs for ``jwt.decode_complete`` to include ``strict_aud`` option by @&#8203;woodruffw in `#&#8203;923 <https://github.com/jpadilla/pyjwt/pull/923>`__
- Fix docs step by @&#8203;jpadilla in `#&#8203;950 <https://github.com/jpadilla/pyjwt/pull/950>`__
- Fix: Remove an unused variable from example code block by @&#8203;kenkoooo in `#&#8203;958 <https://github.com/jpadilla/pyjwt/pull/958>`__

Added
~~~~~

- Add support for Python 3.12 by @&#8203;hugovk in `#&#8203;910 <https://github.com/jpadilla/pyjwt/pull/910>`__
- Improve performance of ``is_ssh_key`` + add unit test by @&#8203;bdraco in `#&#8203;940 <https://github.com/jpadilla/pyjwt/pull/940>`__
- Allow ``jwt.decode()`` to accept a PyJWK object by @&#8203;luhn in `#&#8203;886 <https://github.com/jpadilla/pyjwt/pull/886>`__
- Make ``algorithm_name`` attribute available on PyJWK by @&#8203;luhn in `#&#8203;886 <https://github.com/jpadilla/pyjwt/pull/886>`__
- Raise ``InvalidKeyError`` on invalid PEM keys to be compatible with cryptography 42.x.x by @&#8203;CollinEMac in `#&#8203;952 <https://github.com/jpadilla/pyjwt/pull/952>`__
- Raise an exception when required cryptography dependency is missing by @&#8203;tobloef in `<https://github.com/jpadilla/pyjwt/pull/963>`__

`v2.8.0 <https://github.com/jpadilla/pyjwt/compare/2.7.0...2.8.0>`__
-----------------------------------------------------------------------

Changed
~~~~~~~

- Update python version test matrix by @&#8203;auvipy in `#&#8203;895 <https://github.com/jpadilla/pyjwt/pull/895>`__

Fixed
~~~~~

Added
~~~~~

- Add ``strict_aud`` as an option to ``jwt.decode`` by @&#8203;woodruffw in `#&#8203;902 <https://github.com/jpadilla/pyjwt/pull/902>`__
- Export PyJWKClientConnectionError class by @&#8203;daviddavis in `#&#8203;887 <https://github.com/jpadilla/pyjwt/pull/887>`__
- Allows passing of ssl.SSLContext to PyJWKClient by @&#8203;juur in `#&#8203;891 <https://github.com/jpadilla/pyjwt/pull/891>`__

`v2.7.0 <https://github.com/jpadilla/pyjwt/compare/2.6.0...2.7.0>`__
-----------------------------------------------------------------------

Changed
~~~~~~~

- Changed the error message when the token audience doesn't match the expected audience by @&#8203;irdkwmnsb `#&#8203;809 <https://github.com/jpadilla/pyjwt/pull/809>`__
- Improve error messages when cryptography isn't installed by @&#8203;Viicos in `#&#8203;846 <https://github.com/jpadilla/pyjwt/pull/846>`__
- Make `Algorithm` an abstract base class by @&#8203;Viicos in `#&#8203;845 <https://github.com/jpadilla/pyjwt/pull/845>`__
- ignore invalid keys in a jwks by @&#8203;timw6n in `#&#8203;863 <https://github.com/jpadilla/pyjwt/pull/863>`__

Fixed
~~~~~

- Add classifier for Python 3.11 by @&#8203;eseifert in `#&#8203;818 <https://github.com/jpadilla/pyjwt/pull/818>`__
- Fix ``_validate_iat`` validation by @&#8203;Viicos in `#&#8203;847 <https://github.com/jpadilla/pyjwt/pull/847>`__
- fix: use datetime.datetime.timestamp function to have a milliseconds by @&#8203;daillouf `#&#8203;821 <https://github.com/jpadilla/pyjwt/pull/821>`__
- docs: correct mistake in the changelog about verify param by @&#8203;gbillig in `#&#8203;866 <https://github.com/jpadilla/pyjwt/pull/866>`__

Added
~~~~~

- Add ``compute_hash_digest`` as a method of ``Algorithm`` objects, which uses
  the underlying hash algorithm to compute a digest. If there is no appropriate
  hash algorithm, a ``NotImplementedError`` will be raised in `#&#8203;775 <https://github.com/jpadilla/pyjwt/pull/775>`__
- Add optional ``headers`` argument to ``PyJWKClient``. If provided, the headers
  will be included in requests that the client uses when fetching the JWK set by @&#8203;thundercat1 in `#&#8203;823 <https://github.com/jpadilla/pyjwt/pull/823>`__
- Add PyJWT._{de,en}code_payload hooks by @&#8203;akx in `#&#8203;829 <https://github.com/jpadilla/pyjwt/pull/829>`__
- Add `sort_headers` parameter to `api_jwt.encode` by @&#8203;evroon in `#&#8203;832 <https://github.com/jpadilla/pyjwt/pull/832>`__
- Make mypy configuration stricter and improve typing by @&#8203;akx in `#&#8203;830 <https://github.com/jpadilla/pyjwt/pull/830>`__
- Add more types by @&#8203;Viicos in `#&#8203;843 <https://github.com/jpadilla/pyjwt/pull/843>`__
- Add a timeout for PyJWKClient requests by @&#8203;daviddavis in `#&#8203;875 <https://github.com/jpadilla/pyjwt/pull/875>`__
- Add client connection error exception by @&#8203;daviddavis in `#&#8203;876 <https://github.com/jpadilla/pyjwt/pull/876>`__
- Add complete types to take all allowed keys into account by @&#8203;Viicos in `#&#8203;873 <https://github.com/jpadilla/pyjwt/pull/873>`__
- Add `as_dict` option to `Algorithm.to_jwk` by @&#8203;fluxth in `#&#8203;881 <https://github.com/jpadilla/pyjwt/pull/881>`__

`v2.6.0 <https://github.com/jpadilla/pyjwt/compare/2.5.0...2.6.0>`__
-----------------------------------------------------------------------

Changed
~~~~~~~

- bump up cryptography >= 3.4.0 by @&#8203;jpadilla in `#&#8203;807 <https://github.com/jpadilla/pyjwt/pull/807>`__
- Remove `types-cryptography` from `crypto` extra by @&#8203;lautat in `#&#8203;805 <https://github.com/jpadilla/pyjwt/pull/805>`__

Fixed
~~~~~

- Invalidate token on the exact second the token expires `#&#8203;797 <https://github.com/jpadilla/pyjwt/pull/797>`__
- fix: version 2.5.0 heading typo by @&#8203;c0state in `#&#8203;803 <https://github.com/jpadilla/pyjwt/pull/803>`__

Added
~~~~~
- Adding validation for `issued_at` when `iat > (now + leeway)` as `ImmatureSignatureError` by @&#8203;sriharan16 in `#&#8203;794 <https://github.com/jpadilla/pyjwt/pull/794>`__

`v2.5.0 <https://github.com/jpadilla/pyjwt/compare/2.4.0...2.5.0>`__
-----------------------------------------------------------------------

Changed
~~~~~~~

- Skip keys with incompatible alg when loading JWKSet by @&#8203;DaGuich in `#&#8203;762 <https://github.com/jpadilla/pyjwt/pull/762>`__
- Remove support for python3.6 by @&#8203;sirosen in `#&#8203;777 <https://github.com/jpadilla/pyjwt/pull/777>`__
- Emit a deprecation warning for unsupported kwargs by @&#8203;sirosen in `#&#8203;776 <https://github.com/jpadilla/pyjwt/pull/776>`__
- Remove redundant wheel dep from pyproject.toml by @&#8203;mgorny in `#&#8203;765 <https://github.com/jpadilla/pyjwt/pull/765>`__
- Do not fail when an unusable key occurs by @&#8203;DaGuich in `#&#8203;762 <https://github.com/jpadilla/pyjwt/pull/762>`__
- Update audience typing by @&#8203;JulianMaurin in `#&#8203;782 <https://github.com/jpadilla/pyjwt/pull/782>`__
- Improve PyJWKSet error accuracy by @&#8203;JulianMaurin in `#&#8203;786 <https://github.com/jpadilla/pyjwt/pull/786>`__
- Mypy as pre-commit check + api_jws typing by @&#8203;JulianMaurin in `#&#8203;787 <https://github.com/jpadilla/pyjwt/pull/787>`__

Fixed
~~~~~

- Adjust expected exceptions in option merging tests for PyPy3 by @&#8203;mgorny in `#&#8203;763 <https://github.com/jpadilla/pyjwt/pull/763>`__
- Fixes for pyright on strict mode by @&#8203;brandon-leapyear in `#&#8203;747 <https://github.com/jpadilla/pyjwt/pull/747>`__
- docs: fix simple typo, iinstance -> isinstance by @&#8203;timgates42 in `#&#8203;774 <https://github.com/jpadilla/pyjwt/pull/774>`__
- Fix typo: priot -> prior by @&#8203;jdufresne in `#&#8203;780 <https://github.com/jpadilla/pyjwt/pull/780>`__
- Fix for headers disorder issue by @&#8203;kadabusha in `#&#8203;721 <https://github.com/jpadilla/pyjwt/pull/721>`__

Added
~~~~~

- Add to_jwk static method to ECAlgorithm by @&#8203;leonsmith in `#&#8203;732 <https://github.com/jpadilla/pyjwt/pull/732>`__
- Expose get_algorithm_by_name as new method by @&#8203;sirosen in `#&#8203;773 <https://github.com/jpadilla/pyjwt/pull/773>`__
- Add type hints to jwt/help.py and add missing types dependency by @&#8203;kkirsche in `#&#8203;784 <https://github.com/jpadilla/pyjwt/pull/784>`__
- Add cacheing functionality for JWK set by @&#8203;wuhaoyujerry in `#&#8203;781 <https://github.com/jpadilla/pyjwt/pull/781>`__

`v2.4.0 <https://github.com/jpadilla/pyjwt/compare/2.3.0...2.4.0>`__
-----------------------------------------------------------------------

Security

Changed


- Explicit check the key for ECAlgorithm by @&#8203;estin in `#&#8203;713 <https://github.com/jpadilla/pyjwt/pull/713>`__
- Raise DeprecationWarning for jwt.decode(verify=...) by @&#8203;akx in `#&#8203;742 <https://github.com/jpadilla/pyjwt/pull/742>`__

Fixed
~~~~~

- Don't use implicit optionals by @&#8203;rekyungmin in `#&#8203;705 <https://github.com/jpadilla/pyjwt/pull/705>`__
- documentation fix: show correct scope for decode_complete() by @&#8203;sseering in `#&#8203;661 <https://github.com/jpadilla/pyjwt/pull/661>`__
- fix: Update copyright information by @&#8203;kkirsche in `#&#8203;729 <https://github.com/jpadilla/pyjwt/pull/729>`__
- Don't mutate options dictionary in .decode_complete() by @&#8203;akx in `#&#8203;743 <https://github.com/jpadilla/pyjwt/pull/743>`__

Added
~~~~~

- Add support for Python 3.10 by @&#8203;hugovk in `#&#8203;699 <https://github.com/jpadilla/pyjwt/pull/699>`__
- api_jwk: Add PyJWKSet.__getitem__ by @&#8203;woodruffw in `#&#8203;725 <https://github.com/jpadilla/pyjwt/pull/725>`__
- Update usage.rst by @&#8203;guneybilen in `#&#8203;727 <https://github.com/jpadilla/pyjwt/pull/727>`__
- Docs: mention performance reasons for reusing RSAPrivateKey when encoding by @&#8203;dmahr1 in `#&#8203;734 <https://github.com/jpadilla/pyjwt/pull/734>`__
- Fixed typo in usage.rst by @&#8203;israelabraham in `#&#8203;738 <https://github.com/jpadilla/pyjwt/pull/738>`__
- Add detached payload support for JWS encoding and decoding by @&#8203;fviard in `#&#8203;723 <https://github.com/jpadilla/pyjwt/pull/723>`__
- Replace various string interpolations with f-strings by @&#8203;akx in `#&#8203;744 <https://github.com/jpadilla/pyjwt/pull/744>`__
- Update CHANGELOG.rst by @&#8203;hipertracker in `#&#8203;751 <https://github.com/jpadilla/pyjwt/pull/751>`__

`v2.3.0 <https://github.com/jpadilla/pyjwt/compare/2.2.0...2.3.0>`__
-----------------------------------------------------------------------

Fixed
~~~~~

- Revert "Remove arbitrary kwargs." `#&#8203;701 <https://github.com/jpadilla/pyjwt/pull/701>`__

Added
~~~~~

- Add exception chaining `#&#8203;702 <https://github.com/jpadilla/pyjwt/pull/702>`__

`v2.2.0 <https://github.com/jpadilla/pyjwt/compare/2.1.0...2.2.0>`__
-----------------------------------------------------------------------

Changed
  • Remove arbitrary kwargs. #&#8203;657 <https://github.com/jpadilla/pyjwt/pull/657>__
  • Use timezone package as Python 3.5+ is required. #&#8203;694 <https://github.com/jpadilla/pyjwt/pull/694>__

Fixed

- Assume JWK without the "use" claim is valid for signing as per RFC7517 `#&#8203;668 <https://github.com/jpadilla/pyjwt/pull/668>`__
- Prefer `headers["alg"]` to `algorithm` in `jwt.encode()`. `#&#8203;673 <https://github.com/jpadilla/pyjwt/pull/673>`__
- Fix aud validation to support {'aud': null} case. `#&#8203;670 <https://github.com/jpadilla/pyjwt/pull/670>`__
- Make `typ` optional in JWT to be compliant with RFC7519. `#&#8203;644 <https://github.com/jpadilla/pyjwt/pull/644>`__
-  Remove upper bound on cryptography version. `#&#8203;693 <https://github.com/jpadilla/pyjwt/pull/693>`__

Added
  • Add support for Ed448/EdDSA. #&#8203;675 <https://github.com/jpadilla/pyjwt/pull/675>__

v2.12.0

Compare Source

Security
What's Changed
New Contributors

Full Changelog: jpadilla/pyjwt@2.11.0...2.12.0

v2.11.0

Compare Source

What's Changed
New Contributors

Configuration

📅 Schedule: Branch creation - "" (UTC), Automerge - At any time (no schedule defined).

🚦 Automerge: Disabled by config. Please merge this manually once you are satisfied.

Rebasing: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 Ignore: Close this PR and you won't be reminded about these updates again.


  • If you want to rebase/retry this PR, check this box

This PR has been generated by Renovate Bot.

@platform-automation-dnastack
Copy link
Copy Markdown

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Mar 14, 2026

☂️ Python Coverage

current status: ✅

Overall Coverage

Lines Covered Coverage Threshold Status
11120 6645 60% 30% 🟢

New Files

No new covered files...

Modified Files

No covered modified files...

updated for commit: 9a910d9 by action🐍

@dnastack-renovate dnastack-renovate Bot force-pushed the renovate/pypi-pyjwt-vulnerability branch 3 times, most recently from 627672f to 67ae886 Compare March 25, 2026 18:21
@dnastack-renovate dnastack-renovate Bot force-pushed the renovate/pypi-pyjwt-vulnerability branch 2 times, most recently from 39ef5ba to 6b60456 Compare April 1, 2026 19:51
@dnastack-renovate dnastack-renovate Bot force-pushed the renovate/pypi-pyjwt-vulnerability branch from 6b60456 to d2a1b80 Compare April 15, 2026 21:18
@dnastack-renovate dnastack-renovate Bot force-pushed the renovate/pypi-pyjwt-vulnerability branch from d2a1b80 to 8ae8c64 Compare April 23, 2026 20:25
@dnastack-renovate dnastack-renovate Bot force-pushed the renovate/pypi-pyjwt-vulnerability branch from 8ae8c64 to 2ab08c9 Compare May 1, 2026 00:01
@codecov-commenter
Copy link
Copy Markdown

codecov-commenter commented May 1, 2026

⚠️ Please install the 'codecov app svg image' to ensure uploads and comments are reliably processed by Codecov.

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 59.75%. Comparing base (8186ed1) to head (e6e2828).
⚠️ Report is 2 commits behind head on main.
❗ Your organization needs to install the Codecov GitHub app to enable full functionality.

Additional details and impacted files
@@            Coverage Diff             @@
##             main     #159      +/-   ##
==========================================
+ Coverage   59.59%   59.75%   +0.16%     
==========================================
  Files         180      181       +1     
  Lines       11056    11120      +64     
==========================================
+ Hits         6589     6645      +56     
- Misses       4467     4475       +8     
Flag Coverage Δ
unittests 59.75% <ø> (+0.16%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@dnastack-renovate dnastack-renovate Bot force-pushed the renovate/pypi-pyjwt-vulnerability branch from 2ab08c9 to e6e2828 Compare May 5, 2026 17:15
@dnastack-renovate dnastack-renovate Bot force-pushed the renovate/pypi-pyjwt-vulnerability branch from e6e2828 to 9a910d9 Compare May 21, 2026 22:08
@dnastack-renovate dnastack-renovate Bot changed the title [CU-86b4umhm1] Update dependency pyjwt to v2.12.0 [SECURITY] [CU-86b4umhm1] Update dependency pyjwt to v2.13.0 [SECURITY] Jun 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Development

Successfully merging this pull request may close these issues.

2 participants