Jul 25, 2026·6 min read·6 visits
A recursive object merge flaw in Quasar's 'extend' utility allows attackers to pollute Object.prototype via '__proto__' injection, risking arbitrary code execution or application bypasses.
A prototype pollution vulnerability (CWE-1321) in the Quasar framework's utility function 'extend' allows unauthenticated remote attackers to modify the global Object.prototype. This vulnerability can lead to application-level logic bypasses, denial of service, or potentially arbitrary code execution depending on downstream implementation.
The Quasar framework is a high-performance Vue.js-based framework used for building responsive user interfaces. Its core utility library contains a deeply recursive object-merging utility named extend. This utility is regularly employed to construct configuration settings, handle user options, and update reactive state elements.
A security vulnerability exists in versions of quasar prior to 2.22.0 where the extend utility fails to sanitize object keys during deep merge operations. This allows untrusted input containing prototype-modifying properties to reach the base JavaScript Object.prototype. The exposure of this utility to unsanitized external payloads represents a significant attack surface in web applications.
Successful exploitation of prototype pollution (CWE-1321) enables attackers to inject properties globally across the execution environment. Depending on how downstream application logic references properties of plain JavaScript objects, this pollution can manifest as validation bypasses, state corruption, or denial of service.
The core defect resides in the recursive merge algorithm implemented within the path ui/src/utils/extend/extend.js. The extend function accepts multiple arguments, where the first argument optionally defines the merge depth flag, the second acts as the target, and subsequent objects serve as sources. When the deep-merge boolean is set to true, the utility performs a recursive copy of nested properties.
During a recursive copy, the loop retrieves each source property key and evaluates the target object's corresponding property via the lookup src = target[name]. If a source object contains a nested structure under the key __proto__, the JavaScript engine resolves target['__proto__'] as a reference to the prototype of the target, pointing directly to Object.prototype.
Because the code does not intercept or discard keys named __proto__, the function treats Object.prototype as a valid plain object target. The utility recursively calls extend(deep, clone, copy), assigning the values defined in the malicious source payload onto Object.prototype. This permanently injects the specified properties into all standard objects instantiated in the runtime environment.
Analyzing the vulnerable codebase reveals how the recursive mechanism handles the payload. The critical vulnerability path executes when the deep-merge conditions, source validity, and plain object checks are met. Below is the vulnerable segment inside ui/src/utils/extend/extend.js:
for (; i < length; i++) {
if ((options = args[i]) !== null) {
for (name in options) {
src = target[name] // Resolves target['__proto__'] -> Object.prototype
copy = options[name]
if (target === copy) {
continue
}
if (
deep &&
copy &&
((copyIsArray = Array.isArray(copy)) || isPlainObject(copy))
) {
if (copyIsArray) {
clone = Array.isArray(src) ? src : []
} else {
// Object.prototype qualifies as a plain object
clone = isPlainObject(src) ? src : {}
}
target[name] = extend(deep, clone, copy) // Recursion modifies Object.prototype
} else if (copy !== void 0) {
target[name] = copy
}
}
}
}To remediate this behavior, the framework maintainers implemented an explicit validation filter inside the key iteration loop. The patch skips keys matching __proto__ entirely, stopping the traversal before evaluating the nested properties:
for (; i < length; i++) {
if ((options = args[i]) !== null) {
for (name in options) {
// Explicit block of prototype pollution vector
if (name === '__proto__') {
continue
}
src = target[name]
copy = options[name]
// ... remaining logicAlthough blocking __proto__ successfully eliminates the primary vector, security analysts must evaluate the constructor.prototype bypass technique. This vector uses { "constructor": { "prototype": { "polluted": "yes" } } } to traverse the prototype. However, in this specific implementation, Quasar's isPlainObject function returns false for function constructors, which forces the merger to assign a new, isolated object rather than descending into the global prototype.
Exploitation of this vulnerability requires that an attacker can feed an arbitrary object payload into an application path that invokes Quasar's extend utility with deep-copying enabled. Typical delivery vectors include REST API endpoints accepting JSON inputs, query-string parsers, or client-side form fields.
The attacker structures the JSON payload to target the prototype sequence. When the application executes extend(true, {}, payload), the runtime environment processes the __proto__ key, leading to global pollution. A standard proof-of-concept payload demonstrates this effect:
import { extend } from 'quasar';
// Clean up any existing pollution in the execution scope
delete Object.prototype.polluted;
// Trigger the vulnerability using a crafted JSON object
extend(true, {}, {
['__proto__']:
polluted: 'yes'
}
});
// Verify global pollution on a newly instantiated plain object
if (({}).polluted === 'yes') {
console.log("Status: VULNERABLE");
}The practical outcome is that the property polluted with the value yes is added to Object.prototype. Consequently, any future object declaration, such as let obj = {}, will automatically inherit the property polluted. In production systems, attackers can leverage this behavior to inject properties used by configuration loaders or security filters.
The impact of prototype pollution depends heavily on the execution environment and downstream code execution paths. In Node.js server-side environments, if polluted properties are matched with configuration parameters of utility libraries or child process spawners, this can transition into remote code execution.
In client-side environments, prototype pollution is commonly chained to trigger Cross-Site Scripting (XSS) or to alter application state logic. For example, if a Vue component checks for an optional configuration property that defaults to undefined, an attacker can define that property globally to alter UI layouts, bypass authentication checks, or override data validation parameters.
Due to the complexity of finding exploitable sinks in every target application, CVSS has rated this with a Base Score of 5.6. It carries a CVSS Vector of CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:L, reflecting that exploitation requires specific configuration conditions on the target system.
The primary mitigation is to upgrade the quasar package to version 2.22.0 or higher. This release integrates the validation filter that safely discards __proto__ input keys during runtime execution.
For legacy environments where direct package upgrades are blocked by compatibility constraints, developers should sanitize incoming payloads before processing them. Implementing a pre-merge validation layer that blocks keys such as __proto__, constructor, and prototype prevents malicious payloads from reaching the utility function.
Organizations should also adopt runtime defenses such as freezing the global prototype via Object.freeze(Object.prototype) in non-browser environments. This preventive measure stops any runtime modifications to the base prototype, neutralizing the vulnerability class entirely.
CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:L| Product | Affected Versions | Fixed Version |
|---|---|---|
quasar Quasar Framework | < 2.22.0 | 2.22.0 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-1321 |
| Attack Vector | Network (AV:N) |
| CVSS Base Score | 5.6 |
| Impact | Low Integrity, Low Confidentiality, Low Availability |
| Exploit Status | Proof-of-concept available |
| CISA KEV Status | Not Listed |
The product receives input from an upstream component, but does not neutralize or incorrectly neutralizes special elements that could modify the prototype of an object, leading to modification of attributes on all objects of that type.
A critical-severity template injection vulnerability in Oh My Posh allows for unauthenticated arbitrary command execution. This issue occurs when a user navigates their shell into a directory whose name contains malicious Go template syntax, which is subsequently parsed and executed by the prompt engine.
A critical connection-level Denial of Service (DoS) vulnerability exists in the Yamux stream multiplexer implementation of py-libp2p (versions <= 0.6.0). The flaw allows unauthenticated or authenticated peers to permanently stall a Yamux multiplexed connection by transmitting a single malformed 12-byte header claiming an oversized payload while withholding the payload bytes.
An unauthenticated remote resource exhaustion vulnerability in Amazon aws-smithy-http-server enables denial-of-service (DoS) attacks. Affected versions do not enforce connection limits or header timeouts, allowing standard Slowloris techniques to block server operations.
An authorization bypass vulnerability in the gRPC Watch API of etcd allows low-privileged users to read keys outside of their authorized range. By utilizing an open-ended range request sentinel, the input is prematurely normalized before RBAC validation, misclassifying a range watch as a single-key point query.
An argument injection vulnerability in the AWS Bedrock AgentCore Python SDK allows authenticated users to execute arbitrary commands inside the Code Interpreter sandbox container via crafted Python package specifiers containing shell metacharacters.
A NULL pointer dereference vulnerability was discovered in the getkin/kin-openapi Go library. When parsing incoming request parameters that are validated against a content map with an empty media type, the openapi3filter request validation engine attempts to resolve an uninitialized schema pointer. This results in an unhandled Go runtime panic and process termination, yielding an unauthenticated, remote Denial of Service vector.