Sep 14, 2026·7 min read·24 visits
Unauthenticated remote prototype pollution in confetti yayson allows process-wide logic corruption, Denial of Service, or Remote Code Execution via structured JSON:API documents.
A critical prototype pollution vulnerability was discovered in the confetti yayson library prior to version 4.3.0. The library deserializes JSON:API structures into internal cache dictionaries mapped with standard JavaScript objects. An attacker can control the cache keys by supplying '__proto__' in properties like type or id, modifying the prototype of all JavaScript objects process-wide.
The vulnerability designated as CVE-2026-61534 is a critical prototype pollution flaw residing within the yayson NPM library, specifically in its primary deserialization engines: Store and LegacyStore. The yayson library is designed to parse and structure JSON:API compliant payloads, mapping flat resource structures into relational object-oriented representations. Under normal operational circumstances, a server application leverages this library to deserialize untrusted client payloads into internal database models or runtime business objects.
Because the library handles highly nested and relational JSON:API structures, it maintains internal dictionaries to index processed models, associate relationships, and define model schemas. Prior to version 4.3.0, the core data structures utilized for these mapping tables were initialized as standard JavaScript objects, which implicitly inherit properties and methods from Object.prototype. This architectural pattern creates an entry point for prototype pollution because the keys utilized for dictionary lookups are directly derived from values supplied within user-controlled payloads.
An attacker capable of sending structured JSON:API documents can inject properties specifically targeting the prototype chain of standard JavaScript objects. By placing values such as proto within key fields of the JSON:API specification—specifically within the type, id, or relationship name properties—the library inadvertently executes arbitrary property writes onto Object.prototype. The resulting pollution propagates process-wide, altering the behavior of every subsequent object instantiation within the Node.js runtime.
The root cause of CVE-2026-61534 is the insecure initialization and modification of internal lookup caches within both Store and LegacyStore classes. Specifically, the library initializes internal lookup maps, such as models and relations, using standard object literal notation ({}). In JavaScript, an object literal inherits properties from Object.prototype, which includes standard accessors and methods like proto, constructor, and toString.
During the deserialization process, yayson parses the JSON:API payload to build relationships and cache model instances. To dynamically structure the output models, the library retrieves the type field from the client-supplied JSON data and uses this value directly as a key in the internal models dictionary. For example, when executing models[type], if an attacker provides the value proto as the type, the expression resolves to models['proto']. Because models is a plain object, this key accesses its prototype object instead of creating an empty entry.
The critical vulnerability sink occurs when the deserializer attempts to assign the model instance to the cache using the structure models[type][idStr] = model. Since models['proto'] resolves directly to Object.prototype, the assignment translates to Object.prototype[idStr] = model. This step successfully injects the attacker-controlled model object directly into the global prototype chain. This vulnerability falls under the classification of CWE-1321 (Improperly Controlled Modification of Object Prototype Attributes).
To understand the vulnerability on a code level, we analyze the legacy and modern stores before the patch. In src/yayson/store.ts pre-4.3.0, the models reference is initialized using options?.models ?? {}. When processing a resource, the code executes the following block:
if (hasId(model)) {
const idStr = String(model.id)
if (!models[type]) {
models[type] = {}
}
if (!models[type][idStr]) {
models[type][idStr] = model
}
}Because models is initialized as a plain object, models['proto'] is already a truthy value pointing to Object.prototype. As a result, the check !models[type] evaluates to false, and the code skips the initialization block, proceeding directly to assign models['proto'][idStr] = model.
The patch introduced a dedicated defensive module src/yayson/safe.ts which provides helper functions to initialize safe dictionaries and reject dangerous keys:
export function safeObject<T extends object>(): T {
return Object.create(null) as T
}
const UNSAFE_KEYS = new Set<string>(['__proto__', 'constructor', 'prototype'])
export function isUnsafeKey(key: string): boolean {
return UNSAFE_KEYS.has(key)
}By replacing standard object literals with Object.create(null), the resulting dictionary has no prototype properties. Thus, a lookup of models['proto'] evaluates to undefined, preventing any prototype resolution. Additionally, isUnsafeKey intercepts and rejects requests that attempt to use proto, constructor, or prototype during relationship configuration and property iteration.
Exploitation of CVE-2026-61534 requires sending a crafted JSON:API payload to a REST API endpoint that parses user input with a vulnerable version of yayson. The attack can be launched remotely without authentication, provided the endpoint is publicly exposed and does not validate schema types against a strict whitelist prior to invoking yayson deserialization.
The following diagram illustrates the flow of a successful prototype pollution attack via a vulnerable yayson parsing pipeline:
An attacker can perform the exploitation in a single HTTP request. If the target server deserializes the payload, the prototype chain of all subsequently created objects becomes polluted. For instance, if an attacker injects a property such as adminStatus with the value true, any code block checking if (user.adminStatus) on objects that lack this property will resolve to true, completely bypassing authorization controls.
Furthermore, prototype pollution can be leveraged to execute a Denial of Service (DoS) attack. By polluting fundamental object methods like toString or valueOf with a string or primitive value, the attacker can cause immediate application crashes. Whenever the runtime or an external module attempts to serialize or stringify any object, the engine will attempt to execute the polluted primitive as a function, resulting in an unhandled TypeError that terminates the Node.js process.
The impact of CVE-2026-61534 is classified as Critical, with a CVSS v3.1 score of 9.1 (CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:H). While the immediate guaranteed consequence is Denial of Service or logic corruption, the vulnerability can serve as an entry point for Remote Code Execution (RCE) or complete authentication bypass. This depends on the specific libraries and frameworks loaded within the active Node.js process.
In complex modern applications, many utility frameworks (such as templating engines or database query builders) dynamically resolve options and configurations by searching object keys. If an attacker can inject properties into the global object prototype, they can alter the internal options of these libraries. For example, polluting templating options in engines like EJS or Pug has historically allowed attackers to execute arbitrary shell commands on the hosting system.
If the consuming application does not run within an environment containing usable RCE gadgets, the vulnerability still presents severe availability risks. Because Node.js is single-threaded, a single prototype pollution attack that crashes the process disrupts service for all active users. The severity of this impact is mitigated only by the necessity of specific application-level configurations or gadgets to achieve RCE, leading some analysts to propose an alternate high-severity rating of 8.1.
The primary and recommended mitigation is upgrading the yayson package to version 4.3.0 or higher. The maintainers addressed the issue by integrating null-prototype objects and introducing safe iteration mechanisms across all internal caches. This ensures that the prototype chain is isolated from any incoming payload keys.
If upgrading the package immediately is not feasible, security teams can implement network or runtime mitigations. At the runtime level, Node.js processes should be executed with the --disable-proto=throw command-line argument. This flag instructs the V8 engine to throw an exception immediately if any code attempts to access or modify the proto property, effectively blocking the exploitation attempt before it can pollute the global scope.
Additionally, an input validation middleware can be introduced at the application perimeter. This middleware should recursively sanitize all incoming JSON bodies, parsing keys and stripping any keys that match the blacklisted keywords: proto, constructor, and prototype. Implementing this defensive layer provides robust protection against prototype pollution across all parser libraries, not just yayson.
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:H| Product | Affected Versions | Fixed Version |
|---|---|---|
yayson confetti | <= 4.2.0 | 4.3.0 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-1321 |
| Attack Vector | Network (AV:N) |
| CVSS Score | 9.1 (Critical) |
| Exploit Status | Proof of Concept (PoC) Available |
| CISA KEV Status | Not Listed |
| Impact | Integrity and Availability (High) |
The product receives input from an upstream component, but does not neutralize or incorrectly neutralizes the input before using it to modify the attributes of a prototype object.
An inefficient algorithmic complexity vulnerability exists in the npm package decode-uri-component prior to version 0.5.1. When processing malformed URI strings containing invalid percent-escape sequences, the library falls back to a custom decoder that collects distinct percent-encoded runs into a dictionary and executes a full-string regular expression replacement for each entry. Supplying a payload with thousands of distinct percent-encoded sequences alongside a malformed escape triggers quadratic O(K * L) execution time, starving the single-threaded Node.js event loop and resulting in an unauthenticated Denial of Service.
Open Neural Network Exchange (ONNX) versions 1.4.0 prior to 1.22.0 contain a null pointer dereference (CWE-476) and a signed-to-unsigned integer conversion error (CWE-195) in the shape inference functions for the Scan operator. When processing an untrusted ONNX model, the functions ScanInferenceFunction, ScanInferenceFunction_opset8, and ScanInferenceFunction_opset9 fail to validate the presence and value of the required num_scan_inputs attribute. Omitting the attribute results in a direct null pointer dereference that crashes the host process via SIGSEGV, while supplying a negative value triggers an integer wrap-around during type narrowing that leads to an unhandled allocation failure. Notably, models containing a negative num_scan_inputs value bypass standard validation via onnx.checker.check_model().
CVE-2026-91403 is a critical cryptographic trust validation flaw (CWE-327) in the Java Secure Socket Extension (JSSE) component of Oracle Java SE, Oracle GraalVM, and OpenJDK builds. Triggered by the compromise of private signing keys for eight intermediate Certificate Authorities operated by eMudhra (emSign), unpatched Java runtime environments implicitly trust fraudulent TLS and code-signing certificates issued by these compromised intermediates. Because Java disables online certificate revocation checking (OCSP/CRL) by default, an unauthenticated network attacker in an Adversary-in-the-Middle (AiTM) position can intercept, decrypt, and modify encrypted TLS communications or bypass code signature verification without triggering security exceptions.
Open Neural Network Exchange (ONNX) prior to version 1.22.0 contains a memory exhaustion vulnerability (CWE-789) in its Python tensor unpacking helpers and C++ model checker. Specifically, the _unpack_2bit() and _unpack_4bit() functions in onnx.numpy_helper unconditionally resize unpacked NumPy arrays to match attacker-controlled TensorProto.dims metadata without verifying that the underlying raw_data or int32_data buffers contain a corresponding number of packed bits. Furthermore, onnx.checker.check_tensor() previously bypassed length verification for sub-byte data types. Processing an untrusted ONNX model with packed sub-byte tensors (UINT2, INT2, UINT4, INT4, or FLOAT4E2M1) allows an unauthenticated attacker to trigger disproportionate memory allocations from minimal payloads, resulting in an out-of-memory (OOM) crash and denial of service.
An out-of-bounds read vulnerability (CWE-125) exists in the Open Neural Network Exchange (ONNX) library across versions 1.2.1 prior to 1.22.0. The flaw occurs within the shape inference routines for the ConvTranspose operator when processing a model with a weight tensor rank less than three and an omitted kernel_shape attribute. Unchecked indexing into an empty vector triggers a memory segmentation fault, resulting in a Denial of Service (DoS) against applications inspecting or loading untrusted ONNX models.
A session-binding vulnerability in Python Social Auth (social-core) versions prior to 6.2.0 allows an attacker to perform authorization code injection against the OpenID Connect authentication backend. By storing generated OIDC nonces in a global database table without binding them to the initiating browser session, the library accepts any valid, unexpired nonce returned in an ID token regardless of which session originated the authentication transaction. When combined with the default disablement of Proof Key for Code Exchange (PKCE), an attacker who intercepts an unused authorization code can inject it into their own authentication flow to achieve full account takeover.