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·18 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

•38 minutes ago•CVE-2026-67428
8.5

CVE-2026-67428: Server-Side Request Forgery in Flyto2 Core HTTP-Emitting Modules

Flyto2 Core (flyto-core) prior to version 2.26.7 did not utilize its centralized SSRF validation mechanism ('validate_url_with_env_config') across multiple HTTP-emitting modules. This oversight allowed low-privileged users executing automated workflows to perform Server-Side Request Forgery (SSRF) attacks against internal endpoints, loopback interfaces, and cloud provider metadata services.

Alon Barad
Alon Barad
3 views•5 min read
•about 2 hours ago•CVE-2026-67424
8.5

CVE-2026-67424: Server-Side Request Forgery Bypass via Unvalidated Redirects in Flyto2 Core

An SSRF vulnerability exists in Flyto2 Core due to improper validation of intermediate HTTP redirect hops. While the initial request target is validated against an SSRF protection policy, the HTTP client library (aiohttp) transparently follows 30x redirects to local, internal, or cloud metadata endpoints without application-level revalidation.

Alon Barad
Alon Barad
3 views•6 min read
•about 6 hours ago•GHSA-PC2W-4MQ8-32QW
6.5

GHSA-PC2W-4MQ8-32QW: Missing Human-Approval Gate in create_dynatrace_notebook

A logic vulnerability exists in @dynatrace-oss/dynatrace-mcp-server prior to version 1.8.7. The create_dynatrace_notebook tool lacks a human-approval gate, allowing an attacker to exploit indirect prompt injection to force the underlying LLM client to create persistent Dynatrace notebooks without the operator's consent.

Alon Barad
Alon Barad
5 views•8 min read
•about 7 hours ago•CVE-2026-50559
7.5

CVE-2026-50559: Authentication and Authorization Bypass via Parser Differential in Quarkus

A critical authentication and authorization bypass vulnerability in the Quarkus Java framework exists due to a parser differential mismatch between the HTTP security policy layer and downstream handlers. By leveraging encoded reserved characters such as semicolons, slashes, and backslashes, attackers can bypass configured path-based security policies to gain unauthorized access to secure administrative endpoints and static resources.

Alon Barad
Alon Barad
7 views•6 min read
•about 8 hours ago•CVE-2026-11393
9.0

CVE-2026-11393: Code Injection via Improper Triple-Quote Escaping in AWS AgentCore CLI

A critical code injection vulnerability exists in @aws/agentcore CLI (AWS AgentCore CLI) during the Bedrock Agent import lifecycle. An authenticated remote attacker with permissions to configure Bedrock collaborator attributes can inject python code by embedding triple-double-quotes (""") inside the collaborationInstruction metadata field. The CLI formats this metadata directly into a Python docstring in a generated main.py file without adequate escaping, leading to arbitrary code execution when the imported agent is run or deployed.

Alon Barad
Alon Barad
7 views•8 min read
•about 9 hours ago•GHSA-WCHH-9X6H-7F6P
5.9

GHSA-WCHH-9X6H-7F6P: Cryptographic Vulnerabilities and Deprecation of Olm in matrix-commander

GHSA-WCHH-9X6H-7F6P documents the critical deprecation of the cryptographic library libolm (Olm) and its Python binding wrapper python-olm, which matrix-commander depended upon via its downstream client library matrix-nio. Multiple cryptographic vulnerabilities (timing leaks, side-channels, signature malleability, and protocol confusion) were disclosed in 2022 and 2024. Because libolm is unmaintained, Python clients using matrix-commander are considered cryptographically unsafe until migrating to vodozemac.

Amit Schendel
Amit Schendel
6 views•8 min read