Jun 15, 2026·6 min read·12 visits
PyJWT eagerly decodes JWS payload segments before validating the b64=false header configuration, enabling an unauthenticated remote Denial of Service attack via large, dummy payload strings.
PyJWT versions 2.8.0 through 2.12.1 are vulnerable to an unauthenticated Denial of Service (DoS) attack. When verifying detached JSON Web Signatures (JWS) using the unencoded-payload option (RFC 7797, b64=false), the library eagerly decodes the payload segment before verifying the header configuration or the cryptographic signature. This behavior enables a remote, unauthenticated attacker to inject an arbitrarily large payload segment, triggering excessive CPU and memory resource consumption prior to signature validation.
PyJWT is a widely deployed Python implementation of the JSON Web Token (JWT) and JSON Web Signature (JWS) specifications. Modern web applications rely on this library to decode, parse, and verify cryptographically signed tokens presented by untrusted external clients. The vulnerability designated as CVE-2026-48525 exposes these applications to unauthenticated denial of service attacks.
The flaw resides in the handling of detached JSON Web Signatures using the unencoded-payload option defined in RFC 7797. When processing these specific tokens, the library fails to properly restrict resource allocation during the parsing stage. An attacker can exploit this oversight to trigger disproportionate CPU and memory consumption on the application server.
This behavior constitutes a classic work amplification attack vector. The target server expends significant computational resources processing malformed or oversized data before executing cryptographic signature validation. Consequently, even requests containing invalid signatures can successfully exhaust system resources and degrade availability.
The root cause of CVE-2026-48525 lies in the order of operations inside the internal JWS parser within jwt/api_jws.py. Specifically, the internal helper function _load() is responsible for deserializing the incoming compact JWS string. This function splits the token into three distinct segments using the period separator: header, payload, and signature.
Under normal operations, the second segment contains the Base64URL-encoded payload of the JWS token. In vulnerable versions, _load() immediately attempts to decode this second segment using the base64url_decode() function. This decoding step occurs before the parser evaluates the protected header parameters.
Under RFC 7797, when the header specifies "b64": false, the inline payload segment of the JWS must be empty. The library is designed to subsequently discard any decoded inline payload and substitute it with a caller-provided detached payload. However, because the decoding step is executed first, the library processes whatever arbitrary data is present in the second segment, regardless of the header setting.
Comparing the vulnerable and patched code paths in jwt/api_jws.py reveals the structural changes introduced in version 2.13.0. In vulnerable versions, the decoding logic was executed blindly within a simple try-except block. This allowed large payloads to be decoded regardless of the header configurations.
The patch introduces conditional checks that inspect the "b64" header parameter before executing the decoding function. If the header specifies that "b64" is false, the library validates that the incoming payload segment is entirely empty. If the segment contains data, the library raises a DecodeError immediately.
Below is the relevant portion of the patch from commit 95791b1759b8aa4f2203575d344d5c78564cdc81:
# Inside PyJWS._load in jwt/api_jws.py
if header.get("b64", True) is False:
# Detached payload form (RFC 7515 Appendix F): the compact-form
# payload segment must be empty; the caller supplies the actual
# payload via the `detached_payload` argument in decode_complete.
# Skipping the base64 decode here removes an unauthenticated work
# amplifier.
if payload_segment:
raise DecodeError(
"Payload segment must be empty when 'b64' is false."
)
payload = b""
else:
try:
payload = base64url_decode(payload_segment)
except (TypeError, binascii.Error) as err:
raise DecodeError("Invalid payload padding") from errIn addition to the decoding check, the patch introduces stricter validation for the "crit" header list. RFC 7797 mandates that if "b64" is set to false in the protected header, it must also be declared inside the "crit" array. This ensures that parsers that do not understand RFC 7797 will reject the token outright.
Exploiting CVE-2026-48525 requires minimal effort and no authentication. An attacker must identify an application endpoint that accepts detached JWS tokens with unencoded payloads. Because the signature check occurs after the payload decoding step, the attacker does not need a valid cryptographic key.
The attacker constructs a JWS header containing "alg", "b64": false, and "crit": ["b64"]. Instead of leaving the payload segment empty as required by the specification, the attacker inserts a very large block of random Base64URL characters. This string is appended between the header and a dummy signature.
When the server receives the malformed token, the Python interpreter begins allocating memory and utilizing CPU cycles to decode the massive string. If multiple concurrent requests are dispatched, the target server's worker processes will rapidly become saturated. This leads to severe latency or termination via out-of-memory errors.
> [!NOTE] > Because PyJWT is frequently deployed in synchronous Python web frameworks, a single worker process can be blocked entirely while parsing a single malicious token. This amplification effect makes the vulnerability highly efficient for attackers.
The primary impact of CVE-2026-48525 is a localized Denial of Service on the affected application. The vulnerability is assigned a CVSS v3.1 score of 5.3, reflecting a medium severity impact. The attack vector is remote and requires no privileges, giving it a low complexity threshold. While there is no impact on confidentiality or integrity, the availability of the application is degraded.
Systems that run memory-constrained container environments are particularly vulnerable to crashing. When the Python memory allocator attempts to handle multiple concurrent multi-megabyte string decoding operations, the operating system kernel may terminate the process. This causes immediate service disruption for all legitimate users.
Currently, there is no evidence of active exploitation in the wild. However, proof-of-concept analysis indicates that generating an exploit requires minimal technical sophistication.
The standard remediation path is upgrading the PyJWT dependency to version 2.13.0 or higher. This version implements the necessary validation checks to discard non-compliant tokens before executing expensive decoding steps. Software developers should update their requirements files and rebuild container images accordingly.
For environments where immediate updates are not feasible, temporary workarounds can mitigate the risk. Implementing strict input validation filters on incoming request sizes at the reverse proxy or API gateway level is highly recommended. Limiting the maximum allowed length of HTTP authorization headers can block large payloads.
Network monitoring tools and Web Application Firewalls can be configured to inspect JWS patterns. Requests containing extremely large JWS headers or payload segments that do not conform to expected application constraints should be dropped. Developers should also audit their codebase to verify whether the detached_payload parameter is used in their JWS parsing implementations.
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L| Product | Affected Versions | Fixed Version |
|---|---|---|
PyJWT PyJWT Project | >= 2.8.0, <= 2.12.1 | 2.13.0 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-400 |
| Attack Vector | Network (AV:N) |
| CVSS Score | 5.3 (Medium) |
| Exploit Status | PoC Analysis / None |
| KEV Status | Not Listed |
The program does not properly control the allocation and maintenance of a limited resource on behalf of an actor, enabling a Denial of Service.
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.
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.
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.
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.
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.
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.