Oct 30, 2026·10 min read·5 visits
Prior to version 1.7.6, joserfc split compact JWS and JWE tokens into byte segments in memory before verifying token size limits. Unauthenticated attackers can send oversized tokens to trigger memory allocation amplification and crash application workers via Out-Of-Memory (OOM) conditions.
CVE-2026-119284 (GHSA-9pg5-8c7x-5hfx) is an uncontrolled resource consumption vulnerability (CWE-400) in the compact serialization deserialization routines of joserfc prior to version 1.7.6. The library enforced individual segment size limits only after invoking Python's bytes.split(b'.') on untrusted input tokens. By sending oversized compact JWS or JWE tokens, an unauthenticated remote attacker can force the Python interpreter to duplicate and allocate memory for every segment before size validation executes, resulting in memory exhaustion and an Endpoint Denial of Service (DoS).
joserfc is a Python library maintained by the Authlib project that provides implementations of the Javascript Object Signing and Encryption (JOSE) standards, specifically RFC 7515 (JSON Web Signature), RFC 7516 (JSON Web Encryption), and RFC 7797 (JWS Unencoded Payload Option). Web applications and API gateways frequently integrate joserfc into authentication middleware to parse, validate, and decrypt incoming bearer tokens and encrypted payloads provided by untrusted clients.
When processing JOSE tokens in compact serialization format, the library parses ASCII period-delimited (.) base64url strings into distinct structural segments. A compact JWS contains three segments (header, payload, and signature), whereas a compact JWE contains five segments (protected header, encrypted key, initialization vector, ciphertext, and authentication tag). Because token parsing occurs prior to cryptographic verification, the deserialization functions represent a direct, unauthenticated attack surface for any network-accessible endpoint accepting JOSE tokens.
A vulnerability classified under CWE-400 (Uncontrolled Resource Consumption) exists in joserfc versions prior to 1.7.6. Although the library implements configurable per-segment size limits via its JWSRegistry and JWERegistry classes to prevent Denial of Service (DoS) attacks from oversized tokens, the compact deserialization functions executed these checks too late in the parsing lifecycle.
Specifically, joserfc invoked Python's built-in bytes.split(b".") method on the raw input byte string before evaluating the size of the token. Consequently, an unauthenticated attacker can transmit an arbitrarily large byte sequence that forces the Python runtime to allocate new contiguous memory buffers for each split segment before raising an ExceededSizeError, resulting in memory exhaustion and worker process termination.
The root cause of CVE-2026-119284 lies in the ordering of validation versus memory allocation operations within extract_rfc7515_compact (located in src/joserfc/_rfc7797/compact.py) and extract_compact (located in src/joserfc/_rfc7516/compact.py). To protect against resource exhaustion, JWSRegistry and JWERegistry define explicit boundary attributes such as max_header_length, max_payload_length, max_signature_length, and max_ciphertext_length. However, the deserialization routines relied solely on post-split segment validation methods like validate_header_size() to enforce these thresholds.
In CPython, calling value.split(b".") on a bytes object invokes the underlying C implementation (stringlib_split / bytes_split). This operation scans the input buffer for the 0x2e (.) delimiter, allocates a new Python list object, and then allocates a distinct, newly copied bytes object on the heap for every single segment found in the input. Because bytes objects in Python are immutable, CPython does not use zero-copy memory views during .split(); instead, it duplicates the underlying byte slices in physical memory.
When an application passes an oversized untrusted token (for example, a 250 MB payload contained in an HTTP request body) to joserfc, the initial 250 MB buffer is already resident in process memory. Executing value.split(b".") immediately forces the allocator to provision an additional 250 MB of heap space across the resulting segment objects. Furthermore, if the attacker includes millions of period delimiters without large payloads, CPython allocates a PyBytesObject header and list pointer for each empty segment, adding significant metadata overhead.
Only after bytes.split(b".") completes all memory allocations and verifies the segment count (len(parts) != 3 for JWS or len(parts) != 5 for JWE) does execution reach registry.validate_header_size(). By the time the size check is evaluated, the peak memory amplification has already occurred. If the duplicated buffers exceed the available system RAM or container cgroup memory limits, the Python interpreter either raises an unhandled MemoryError or is immediately terminated by the operating system kernel's Out-Of-Memory (OOM) killer.
Prior to version 1.7.6, the compact deserialization functions extracted segments directly from the unvalidated value parameter. In src/joserfc/_rfc7797/compact.py, extract_rfc7515_compact split the input bytes immediately upon entry, deferring registry initialization and boundary checks until after the segments were unpacked.
# Vulnerable implementation in src/joserfc/_rfc7797/compact.py (< 1.7.6)
def extract_rfc7515_compact(value: bytes, registry: JWSRegistry | None = None) -> CompactSignature:
# FLAW: Allocates new bytes objects for every segment before checking input length
parts = value.split(b".")
if len(parts) != 3:
raise DecodeError("Invalid JSON Web Signature")
if registry is None:
registry = default_registry
header_segment, payload_segment, signature_segment = parts
# Validation occurs only after memory duplication has already succeeded
registry.validate_header_size(header_segment)
registry.validate_payload_size(payload_segment)
registry.validate_signature_size(signature_segment)
...Commit 397e04f4bbce0b94d86e31c1c003f4640af8fb39 resolves this vulnerability by introducing a pre-split aggregate size check method, validate_compact_value_size(), on both JWSRegistry and JWERegistry. This method calculates the sum of the maximum permissible lengths of all individual segments and compares it against len(value) before value.split(b".") is called.
# Patched implementation in src/joserfc/_rfc7515/registry.py (1.7.6)
def validate_compact_value_size(self, value: bytes) -> None:
# Compute maximum aggregate size across all 3 JWS segments
max_length = self.max_header_length + self.max_payload_length + self.max_signature_length
# O(1) length check reads PyVarObject.ob_size without copying memory
if value and len(value) > max_length:
raise ExceededSizeError(f"Value size exceeds {max_length} bytes.")An identical method was added to JWERegistry in src/joserfc/_rfc7516/registry.py to sum all five JWE component maximums (max_protected_header_length, max_encrypted_key_length, max_initialization_vector_length, max_ciphertext_length, and max_auth_tag_length). Both extract_rfc7515_compact and extract_compact were then updated to invoke registry.validate_compact_value_size(value) as their first operation.
# Patched implementation in src/joserfc/_rfc7797/compact.py (1.7.6)
def extract_rfc7515_compact(
value: bytes, registry: JWSRegistry | None = None
) -> CompactSignature:
if registry is None:
registry = default_registry
# FIX: Reject oversized input in O(1) time before invoking .split()
registry.validate_compact_value_size(value)
parts = value.split(b".")
if len(parts) != 3:
raise DecodeError("Invalid JSON Web Signature")
header_segment, payload_segment, signature_segment = parts
registry.validate_header_size(header_segment)
...> [!NOTE]
> Assessment of Fix Completeness: Evaluating len(value) on a Python bytes object is an $O(1)$ operation that reads the ob_size field directly from the C PyVarObject struct without allocating memory. While an attacker can still craft an asymmetric token where a single segment consumes the entire aggregate budget (e.g., a header of length max_header + max_payload + max_signature with empty payload and signature segments) to trigger a .split() call, total memory allocation is strictly bounded by the sum of the configured limits. The fix completely prevents unbounded memory amplification within joserfc.
Exploiting CVE-2026-119284 requires no authentication, cryptographic material, or prior knowledge of the target application's signing keys. The only prerequisite is network access to an endpoint that passes client-supplied input to joserfc compact deserialization functions (such as joserfc.jws.deserialize_compact, joserfc.jwe.decrypt_compact, or joserfc.jwt.decode) without enforcing strict upstream HTTP payload size restrictions.
To execute the attack, an adversary constructs a synthetic compact token formatted as three (for JWS) or five (for JWE) period-separated byte strings (<segment_1>.<segment_2>.<segment_3>), or a massive byte string containing arbitrary period delimiters. Because HTTP servers commonly restrict the size of HTTP request headers (such as Authorization: Bearer <token>) to 8 KB – 64 KB by default, the primary vector for high-amplification exploitation is endpoints that accept tokens inside HTTP POST/PUT request bodies (for example, JSON payloads in OAuth2/OIDC token introspection, token exchange, or webhook verification endpoints).
When the attacker transmits concurrent HTTP requests containing multi-megabyte token strings to the target endpoint, each WSGI/ASGI worker process reads the request body into memory and passes the raw bytes to joserfc. Upon calling value.split(b"."), each worker duplicates the payload in heap memory. Below is a representation of how an oversized input triggers the amplification loop prior to rejection:
import joserfc.jws
from joserfc.errors import ExceededSizeError
# Construct a 100 MB payload formatted as a 3-segment JWS
segment = b"A" * (33 * 1024 * 1024)
oversized_token = b".".join([segment, segment, segment]) # ~99 MB in memory
try:
# In joserfc < 1.7.6, extract_rfc7515_compact calls oversized_token.split(b".")
# This allocates an additional ~99 MB for the 3 segment slices before raising ExceededSizeError
joserfc.jws.deserialize_compact(oversized_token, public_key)
except ExceededSizeError:
passAs concurrent requests arrive across multiple threads or worker processes, the cumulative memory footprint spikes rapidly. Once the aggregate allocation crosses the host or container memory boundary, the operating system kernel invokes the OOM killer (oom_reaper), terminating the Python application worker processes and dropping all active client connections handled by those workers.
The security impact of CVE-2026-119284 is confined to system availability, with no direct impact on confidentiality (VC:N) or integrity (VI:N). The vulnerability is scored at 6.9 (Medium) under the CVSS v4.0 specification (CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:L/SC:N/SI:N/SA:N). The Attack Vector is Network (AV:N), Attack Complexity is Low (AC:L), and Privileges Required is None (PR:N), reflecting that any unauthenticated network client can trigger the memory allocation path.
In production deployments, the severity of the availability degradation depends on the runtime architecture and upstream proxy configuration. Containerized microservices running in Kubernetes pods with strict cgroup memory limits, or serverless functions (such as AWS Lambda) with fixed memory allocations, are particularly susceptible. A small number of concurrent requests carrying oversized tokens can force the container runtime to repeatedly OOM-kill the worker processes, inducing a crash loop that causes a sustained Denial of Service.
In multi-worker WSGI/ASGI deployments (such as Gunicorn or Uvicorn), an OOM termination of a worker process causes all other concurrent in-flight requests assigned to that specific worker to fail abruptly with HTTP 502 (Bad Gateway) or connection reset errors. While the supervisor process will typically respawn the terminated worker, continuous request flooding from an attacker will exhaust process startup capacity and degrade overall service availability.
According to FIRST.org Exploit Prediction Scoring System (EPSS) metrics, CVE-2026-119284 currently holds an EPSS score of 0.00192 (0.19% probability of exploitation in the next 30 days, placing it in the 8.91st percentile). The vulnerability is not listed in the CISA Known Exploited Vulnerabilities (KEV) catalog, and no public weaponized exploits have been observed in the wild as of publication.
The primary remediation is to upgrade joserfc to version 1.7.6 or later. Version 1.7.6 incorporates commit 397e04f4bbce0b94d86e31c1c003f4640af8fb39, which enforces validate_compact_value_size() prior to calling bytes.split(b".") on both JWS and JWE compact inputs. Operators can upgrade the package using pip or update their project dependency manifests:
pip install --upgrade "joserfc>=1.7.6"In addition to upgrading the library, organizations should implement defense-in-depth controls at the reverse proxy, API gateway, or web server layer to prevent arbitrarily large HTTP requests from reaching Python application workers. Even with joserfc 1.7.6, if a reverse proxy buffers and forwards a 500 MB HTTP request body to the Python application, the Python web framework will still allocate the initial 500 MB string before joserfc rejects it. Configuring strict request body and header size limits at the network edge eliminates this overhead:
# Example Nginx configuration restricting header and body sizes
http {
client_max_body_size 1m;
large_client_header_buffers 4 16k;
}For environments where an immediate upgrade to joserfc >= 1.7.6 is not feasible, developers should implement an explicit length check in application code immediately before passing any untrusted string or bytes object into joserfc deserialization routines:
MAX_TOKEN_BYTES = 16384 # 16 KB upper bound for compact tokens
def verify_client_token(raw_token: bytes | str, key):
if len(raw_token) > MAX_TOKEN_BYTES:
raise ValueError("Token exceeds maximum permitted length")
return joserfc.jws.deserialize_compact(raw_token, key)CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:L/SC:N/SI:N/SA:N| Product | Affected Versions | Fixed Version |
|---|---|---|
joserfc Authlib | < 1.7.6 | 1.7.6 |
| Attribute | Detail |
|---|---|
| CVE ID | CVE-2026-119284 (GHSA-9pg5-8c7x-5hfx) |
| Weakness Class | CWE-400 (Uncontrolled Resource Consumption) |
| CVSS v4.0 Score | 6.9 Medium (CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:L/SC:N/SI:N/SA:N) |
| EPSS Score | 0.19% (8.91st Percentile) |
| Attack Vector | Network (Unauthenticated HTTP requests containing oversized JOSE tokens) |
| Security Impact | Endpoint Denial of Service (DoS) via Out-Of-Memory (OOM) termination |
| Patched Version | joserfc >= 1.7.6 |
| CISA KEV Status | Not Listed |
The product does not properly control the allocation and maintenance of a limited resource, thereby enabling an actor to influence the amount of resources consumed, eventually leading to the exhaustion of available resources.
A Time-of-Check to Time-of-Use (TOCTOU) race condition in Charmbracelet Soft Serve versions 0.6.0 through 0.12.2 allows unauthenticated users to retain read access to repositories after their visibility is changed from public to private. The flaw stems from premature cache invalidation in the SetPrivate method prior to committing the visibility update to the underlying database. Concurrent read requests arriving during the database transaction window repopulate the non-expiring in-memory LRU cache with stale public metadata, bypassing access controls across HTTP, SSH, and Git protocols until the server process is restarted.
A resource consumption vulnerability exists in the Authlib joserfc Python library prior to version 1.7.5. When processing JSON Web Encryption (JWE) objects formatted using General JSON Serialization, the library fails to enforce an upper bound on the number of elements within the recipients array. An unauthenticated attacker can supply a JWE containing thousands of recipient entries targeting an RSA key management algorithm, forcing the server to perform an equivalent number of computationally expensive RSA private-key decryption operations per request and exhausting available CPU resources.
An improper input validation vulnerability (CWE-20) exists in the Entity Syntax Tree (EST) JSON deserialization component of the Cedar Policy Language (`cedar-policy` and `@cedar-policy/cedar-wasm`). When parsing JSON-formatted policy templates that define `is ... in` scope constraints on `principal` or `resource`, the parser used wildcard pattern matching that ignored the provided slot identifier (`?principal` or `?resource`). This omission allows malformed JSON templates to bypass initial deserialization validation, resulting in either a runtime panic during template linking or inverted slot bindings that alter authorization outcomes.
The @eeacms/volto-chatbot package for Plone Volto contains an unauthenticated confused deputy vulnerability (CWE-862) in versions 2.0.3 and earlier. The package registers Express middleware on wildcard proxy routes (`**/_v1_da/**` and `**/_v1_ha/**`) without verifying client authentication or restricting target endpoints. When processing incoming HTTP requests, the middleware automatically attaches server-side administrative credentials before forwarding the requests to upstream Danswer (Onyx) or Halloumi (LLMGW) API servers. This allows unauthenticated network attackers to execute arbitrary administrative API calls against the backend infrastructure.
CVE-2026-9705 is an insufficient session expiration and authorization bypass vulnerability in Keycloak and Red Hat build of Keycloak. The vulnerability occurs in the OAuth 2.0 Dynamic Client Registration Management Protocol implementation, where the authentication handler fails to verify whether a target client is enabled before accepting requests authenticated with a previously issued Registration Access Token (RAT). Consequently, an actor possessing a valid RAT for an administratively disabled client can query, update, and re-enable the client configuration, restoring revoked access to realm resources.
CVE-2026-9800 is an authorization bypass vulnerability affecting the Keycloak Policy Enforcer (org.keycloak:keycloak-policy-enforcer), which is integrated into Red Hat build of Keycloak, Red Hat build of Quarkus, Red Hat Single Sign-On 7, and Red Hat JBoss Enterprise Application Platform Expansion Pack. The flaw stems from improper comparison logic in the PolicyEnforcer.isDefaultAccessDeniedUri method, which uses loose substring matching on the full raw request URI rather than exact, normalized path comparisons against the configured access-denied landing page. Consequently, an authenticated attacker possessing any valid low-privileged token can bypass role-based, scope-based, and User-Managed Access (UMA) policy evaluations by embedding the access-denied path segment into the URL path or query parameters.