CVEReports
CVEReports

Automated vulnerability intelligence platform. Comprehensive reports for high-severity CVEs generated by AI.

Product

  • Home
  • Sitemap
  • RSS Feed

Company

  • About
  • Contact
  • Privacy Policy
  • Terms of Service

© 2026 CVEReports. All rights reserved.

Made with love by Amit Schendel & Alon Barad



CVE-2026-48524

CVE-2026-48524: Remote Cache Eviction and Authentication Denial of Service in PyJWT

Alon Barad
Alon Barad
Software Engineer

Jun 15, 2026·8 min read·15 visits

Executive Summary (TL;DR)

Unauthenticated attackers can send JWTs with randomized KIDs to force connection errors on the target's upstream JWKS endpoint. A flaw in the error cleanup sequence then writes None to the cache, evicting all legitimate signing keys and preventing legitimate users from authenticating.

A logic flaw in PyJWT's PyJWKClient class allows remote unauthenticated attackers to trigger a complete authentication outage. By transmitting a volume of JWTs containing randomized, non-existent Key ID (kid) values, attackers force synchronous outbound JWKS resolution queries. When these queries fail or time out, a defect in the error cleanup code overwrites the local cache of valid signing keys with None, causing a denial of service.

Vulnerability Overview

The pyjwt library provides a widely adopted interface for encoding and decoding JSON Web Tokens (JWT) in Python. When deploying applications with asymmetric cryptography (such as RS256, ES256, or PS256), the verifying party requires access to the corresponding public key. The standard mechanism for dynamic key distribution is a JSON Web Key Set (JWKS), typically served over HTTPS by an Identity Provider (IdP) such as Auth0, Keycloak, or Okta. To optimize performance and reduce latency, the PyJWKClient class includes an in-memory caching mechanism (JWKSetCache) that stores retrieved keys, mitigating the need to query the remote JWKS endpoint on every token validation attempt.

A critical design choice in many JWT libraries, including legacy versions of pyjwt, is the parsing of the JWT header prior to cryptographic signature verification. The header contains metadata such as the Key ID (kid), which indicates which specific key from the JWK Set should be used to verify the signature. Because the kid is extracted from the unverified header, an attacker can manipulate this value arbitrarily. This exposes a significant attack surface: any incoming request containing a syntactically valid JWT, regardless of its signature validity, is processed by the verification pipeline up to the point of key retrieval.

CVE-2026-48524 describes a logical vulnerability in the handling of network errors during the retrieval of JWK Sets. When an unauthenticated remote attacker floods the target application with JWTs containing randomized, non-existent kid headers, the application attempts to resolve these keys by querying the remote JWKS endpoint. If these synchronous outbound queries fail—either due to rate-limiting by the IdP or socket timeouts—the cache-clearing logic in PyJWKClient is triggered. This behavior transforms a transient network error or rate-limiting event into a complete, application-wide authentication outage.

Root Cause Analysis

The root cause of CVE-2026-48524 lies in the exception-handling structure of the fetch_data method inside jwt/jwks_client.py. In Python, the finally block in a try-except-else-finally statement is guaranteed to execute regardless of whether an exception is raised, caught, or propagated. Prior to version 2.13.0, PyJWKClient.fetch_data utilized this construct to populate its local cache. The local variable jwk_set was initialized to None at the entry of the method.

During normal operations, a successful HTTP request populates jwk_set with the parsed dictionary containing the keys, which is then written to the cache via self.jwk_set_cache.put(jwk_set). However, if the outbound connection fails—due to connection reset, DNS failure, HTTP 429 rate limits, or read timeout—the interpreter raises an exception inside the try block. This exception is caught in the except block, which raises a PyJWKClientConnectionError. Before the exception propagates up the call stack to the caller, control is transferred to the finally block.

At this execution state, the jwk_set variable remains bound to its initial value of None. The conditional check if self.jwk_set_cache is not None: evaluates to true. Consequently, the interpreter executes self.jwk_set_cache.put(None). The cache backend implements a simple key-value replacement strategy. Writing None to the cache overwrites and effectively evicts the previously stored, valid JWK Set. This represents an instance of CWE-460 (Improper Cleanup on Thrown Exception) working in conjunction with CWE-755 (Improper Handling of Exceptional Conditions).

Code Analysis

To understand the mechanics of the vulnerability and its remediation, we examine the logical transition between the vulnerable implementation and the patch introduced in version 2.13.0. The fundamental flaw was the placement of state-altering cache writes within the non-conditional cleanup path of the finally block.

# VULNERABLE CODE PATH (jwt/jwks_client.py)
def fetch_data(self) -> Any:
    jwk_set: Any = None
    try:
        # Outbound network IO is initiated here
        r = urllib.request.Request(url=self.uri, headers=self.headers)
        with urllib.request.urlopen(
            r, timeout=self.timeout, context=self.ssl_context
        ) as response:
            jwk_set = json.loads(response.read().decode("utf-8"))
    except Exception as e:
        # Any network failure or timeout redirects here
        raise PyJWKClientConnectionError(
            f'Fail to fetch data from the url, err: "{e}"'
        ) from e
    else:
         return jwk_set
    finally:
        # EXPLOITATION POINT: This block always runs
        # If an exception was raised, jwk_set remains None
        if self.jwk_set_cache is not None:
            self.jwk_set_cache.put(jwk_set) # Cache is overwritten with None

The remediation in version 2.13.0 completely refactors the control flow to isolate the cache-write operation from the exception handling sequence. By removing the finally block entirely, the library guarantees that the cache state is mutated only upon successful completion of both the network request and the JSON parsing routine.

# PATCHED CODE PATH (jwt/jwks_client.py)
def fetch_data(self) -> Any:
    try:
        r = urllib.request.Request(url=self.uri, headers=self.headers)
        with urllib.request.urlopen(
            r, timeout=self.timeout, context=self.ssl_context
        ) as response:
            jwk_set = json.loads(response.read().decode("utf-8"))
    except Exception as e:
        raise PyJWKClientConnectionError(
            f'Fail to fetch data from the url, err: "{e}"'
        ) from e
 
    # REMEDIATION: Cache update occurs only after successful retrieval.
    # If fetch fails, the exception is raised, and this block is bypassed.
    if self.jwk_set_cache is not None:
        self.jwk_set_cache.put(jwk_set)
    return jwk_set

While this patch completely resolves the cache eviction flaw (CWE-460), the design of PyJWKClient remains susceptible to network amplification. An attacker sending requests with random kid values can still force the server to initiate synchronous outbound connections. Applications utilizing PyJWKClient must configure appropriate rate limiting or implement caching strategies that penalize missing keys to prevent outbound connection exhaustion.

Exploitation Methodology

An exploitation scenario targeting CVE-2026-48524 does not require cryptographic material or valid user credentials. The attack leverages the target application's willingness to parse JWT headers from unauthenticated requests. The attacker must target an endpoint that relies on dynamic JWKS resolution using PyJWKClient.

The execution flow begins with the generation of automated requests containing JWTs with unique, randomized kid headers. The target application parses each header, notes that the kid is missing from the local cache, and issues a synchronous fetch request to the remote JWKS URI. This process is repeated across a high volume of concurrent threads or connections.

As the rate of outbound queries increases, the Identity Provider (e.g., Auth0 or Keycloak) detects the spike and applies rate-limiting policies, responding with an HTTP 429 Too Many Requests status code. Alternatively, the target application may exhaust its own outbound socket pool, resulting in network connection timeouts. In either case, an exception is thrown in the try block. The finally block executes immediately, writing None to the cache and wiping out the legitimate keys. Subsequent verification attempts for all users fail until a successful outbound request can be completed.

Impact Assessment

The impact of CVE-2026-48524 is classified as a Denial of Service (DoS) affecting the availability of the authentication layer. Because the vulnerability results in the eviction of legitimate public keys from the cache, any application thread trying to validate a standard user token is forced to perform a synchronous outbound request. If the upstream provider is rate-limiting the application, all incoming valid tokens will fail verification, causing a complete lockout of authorized users.

The vulnerability receives a CVSS v3.1 score of 3.7. The High attack complexity reflects the dependency on external environmental conditions, specifically the requirement that the upstream JWKS endpoint fails, rate-limits, or times out. An attacker cannot guarantee the precise timing of this failure, as it depends on network latency, connection pooling, and the rate-limiting thresholds of the specific Identity Provider.

From a business perspective, the consequences can be significant. If a critical service experiences a cache wipe, the authentication layer cannot recover until the upstream provider stops rate-limiting the application server. This creates a feedback loop: as long as the attacker continues to transmit invalid kid headers, the application will continue to trigger rate limits, extending the duration of the service outage indefinitely.

Remediation & Detection Guidance

The primary remediation path is upgrading the pyjwt library to version 2.13.0 or higher. This version removes the vulnerable finally block and ensures that the cache is only updated when a network transaction is completed successfully. This prevents temporary network failures from corrupting the in-memory cache state.

If upgrading is not immediately feasible, organizations can implement several mitigation strategies. First, deploy a Web Application Firewall (WAF) or ingress controller rule to rate-limit requests to endpoints that parse JWTs. Second, implement an application-level middleware to validate the format of the kid header, discarding requests that do not match expected patterns (e.g., specific alphanumeric lengths or UUID formats used by the IdP).

To detect potential exploitation attempts, security operations teams should monitor application logging for high rates of PyJWKClientConnectionError exceptions. Additionally, network monitoring tools should track outbound connections to the JWKS endpoint. A sharp increase in outbound DNS requests or HTTP queries to the authentication provider's domain is a strong indicator of active exploitation or misconfiguration.

Official Patches

Jose PadillaFix commit for cache eviction issue in fetch_data

Fix Analysis (1)

Technical Appendix

CVSS Score
3.7/ 10
CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:N/A:L
EPSS Probability
0.21%
Top 90% most exploited

Affected Systems

Applications utilizing the pyjwt Python package prior to version 2.13.0 with PyJWKClient enabled for dynamic key retrieval.

Affected Versions Detail

Product
Affected Versions
Fixed Version
pyjwt
Jose Padilla
< 2.13.02.13.0
AttributeDetail
CWE IDCWE-460
Attack VectorNetwork
CVSS v3.13.7
EPSS Score0.00205
ImpactDenial of Service (DoS)
Exploit Statusnone
KEV StatusNot Listed

MITRE ATT&CK Mapping

T1499Endpoint Denial of Service
Impact
CWE-460
Improper Cleanup on Thrown Exception

The software does not clean up its state or resources when an exception is thrown, leading to inconsistent states (specifically, storing None in the JWKS cache when a network exception is thrown inside fetch_data()).

Vulnerability Timeline

Vulnerability patched and released in version 2.13.0
2026-05-21
CVE-2026-48524 published to CVE.org
2026-05-28
GitHub Security Advisory published under ID GHSA-fhv5-28vv-h8m8
2026-05-28

References & Sources

  • [1]GitHub Security Advisory GHSA-fhv5-28vv-h8m8
  • [2]Official CVE Record CVE-2026-48524
  • [3]PyJWT Commit Fix 95791b1759b8aa4f2203575d344d5c78564cdc81

Attack Flow Diagram

Press enter or space to select a node. You can then use the arrow keys to move the node around. Press delete to remove it and escape to cancel.
Press enter or space to select an edge. You can then press delete to remove it or escape to cancel.

More Reports

•2 days ago•CVE-2026-54068
5.9

CVE-2026-54068: Unauthenticated Server-Side Template Injection and SQLite Exfiltration in SiYuan PKM

An authentication bypass in the SiYuan personal knowledge management system before version 3.7.0 exposes a dynamic icon rendering endpoint. This endpoint processes client-supplied Go template directives. By submitting a crafted request, an unauthenticated remote attacker can leverage registered database template functions to execute arbitrary read-only SQL queries and exfiltrate workspace contents.

Amit Schendel
Amit Schendel
14 views•5 min read
•2 days ago•CVE-2026-54069
9.1

CVE-2026-54069: Authentication Bypass in SiYuan Note via Origin Header Spoofing

CVE-2026-54069 is a critical authentication bypass vulnerability in the SiYuan Note personal knowledge management system. The flaw is located in the HTTP server's middleware handling API authorization, which unconditionally trusts requests carrying a 'chrome-extension://' scheme in the Origin HTTP header, granting administrative access without validating API tokens.

Alon Barad
Alon Barad
11 views•5 min read
•2 days ago•CVE-2026-54089
9.1

CVE-2026-54089: Authentication Bypass by Spoofing in File Browser

CVE-2026-54089 is a critical authentication bypass vulnerability in File Browser affecting instances configured with proxy-based authentication. An unauthenticated remote attacker with direct network access can impersonate arbitrary users or register new accounts by spoofing configured HTTP headers.

Amit Schendel
Amit Schendel
8 views•7 min read
•2 days ago•GHSA-99J7-FHR2-XFJ4
10.0

GHSA-99J7-FHR2-XFJ4: Malicious Remote Code Execution Payload in 'exploration' Cargo Crate

The malicious Cargo package 'exploration' was uploaded to the crates.io registry. During compilation or package import, the crate executes code designed to establish an outbound TCP/HTTP connection, download an external second-stage binary, and execute the binary locally on the host machine. This creates an unauthenticated remote code execution vector impacting developer environments and continuous integration pipelines.

Amit Schendel
Amit Schendel
11 views•6 min read
•2 days ago•CVE-2026-54088
9.3

CVE-2026-54088: Pre-Authentication Remote Code Execution in File Browser Hook Authentication

CVE-2026-54088 is a critical command injection vulnerability in File Browser prior to version 2.63.6. When Hook Authentication is enabled, the application interpolates unsanitized credentials into a shell command, allowing unauthenticated remote code execution.

Alon Barad
Alon Barad
12 views•6 min read
•2 days ago•GHSA-QV4M-M73M-8HJ7
8.8

GHSA-qv4m-m73m-8hj7: Authenticated Arbitrary File Upload leading to Remote Code Execution in NotrinosERP

An authenticated remote code execution vulnerability exists in NotrinosERP (versions up to and including 1.0.0) within the Human Resource Management (HRM) module. Users with employee management permissions can upload arbitrary file types, including PHP scripts, which are written directly to a web-accessible directory. This allows for arbitrary code execution in the context of the web-server user.

Alon Barad
Alon Barad
8 views•6 min read