Skip to content

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

PyJWKClient unbounded JWKS endpoint requests via attacker-controlled kid values (DoS)

Low PyPI
Severity
3.7 / 10
Low · CVSS 3.1
Exploit chance (EPSS)
0.40%
Chance of exploitation in the next 30 days. Higher than 34.26% of scored vulnerabilities.
Known exploited
No
Not in CISA's catalog
Weakness
CWE-460 Improper Cleanup on Thrown Exception
CWE-755 Improper Handling of Exceptional Conditions
Fix
2.13.0
Upgrade pyjwt to this version or later

Description

[!NOTE] 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. Impact is reduced auth availability until the next successful fetch, not complete denial of service.

Summary

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.

Additionally, fetch_data() finally block clears the JWKS cache on network error.

Root Cause

jwt/jwks_client.py:172-198 - get_signing_key(kid) calls get_signing_keys(refresh=True) for unknown kids, bypassing TTL cache with no cooldown. jwt/jwks_client.py:120-122 - finally block writes None to cache on error, clearing valid data.

Impact

  • DoS against JWKS endpoint (unlimited requests per invalid token)
  • DoS against application (network I/O latency)
  • Cascading failure (rate limiting clears cache, breaking legitimate auth)

Suggested Fix

  1. Add refresh cooldown (refuse refresh more than once per TTL period)
  2. Move cache write from finally to else block

Affected Versions

All versions with PyJWKClient (2.4.0 through 2.12.1)

Affected versions

PyPI

PackageVulnerableFixed in
pyjwt
>= 2.0.0, < 2.13.0
2.13.0
pyjwt
< 2.13.0
2.13.0

How to fix

Move to the fixed version or later with your package manager, update the lockfile, and run your tests. If the package only arrives through another dependency, upgrade that dependency first. If none of its releases pulls a fixed version yet, force the version with your package manager's override.

pyjwt PyPI → 2.13.0

pip
pip install --upgrade "pyjwt>=2.13.0"
poetry
poetry add "pyjwt>=2.13.0"
uv
uv add "pyjwt>=2.13.0"

Severity breakdown

CVSS 3.1 3.7

CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:N/A:L

Attack vector
Network
Attack complexity
High
Privileges required
None
User interaction
None
Scope
Unchanged
Confidentiality
None
Integrity
None
Availability
Low

Weakness

CWE-460: Improper Cleanup on Thrown Exception

The product does not clean up its state or incorrectly cleans up its state when an exception is thrown, leading to unexpected state or control flow.

How to prevent it
  • Implementation: If one breaks from a loop or function by throwing an exception, make sure that cleanup happens or that you should exit the program. Use throwing exceptions sparsely.

CWE-755: Improper Handling of Exceptional Conditions

The product does not handle or incorrectly handles an exceptional condition.

References

Timeline

  1. Published
  2. Last updated by the source
  3. Latest EPSS score
AdvisorySeverityWhy it's related
GHSA-pxh4-856f-4h89
PyJWT: HS256/384/512 verify accepts empty HMAC key via oct JWK (PyJWK/PyJWKClient) enabling token forgery
High Also affects pyjwt
GHSA-gvp8-978c-rx2q
PyJWT.decode() reintroduces options-dict mutation, enabling silent claim-verification bypass on dict reuse
Medium Also affects pyjwt
GHSA-x33g-cr3x-6449
PyJWT accepts inconsistent OKP x/d JWKs, causing public/private key identity confusion
High Also affects pyjwt
GHSA-w6j9-cwv2-h6wq
PyJWT: Malformed RSA JWK aborts parsing of an entire JWK Set
High Also affects pyjwt
GHSA-w2cx-738m-mc7w
PyJWT accepts public JWK containers as HMAC secrets
High Also affects pyjwt
GHSA-r6x4-923q-g947
PyJWT BOM Bypass
High Also affects pyjwt
GHSA-p4g4-x82p-q773
PyJWT: Public keys in DER form are accepted as HMAC secrets, bypassing the CVE-2022-29217 guard
High Also affects pyjwt
GHSA-jwrc-g2q2-pq5p
PyJWT: ReDoS vulnerability when calling the `is_pem_format` function.
Medium Also affects pyjwt
Is this in your code?

MergeHarbor checks every repository's dependencies against this database, ranks what matters by exploitability and reachability, routes it to the owning team and opens the fix pull request.

Check your repos with MergeHarbor