From 7e5a72703d061e41b0146137b80005cfd62ca73e Mon Sep 17 00:00:00 2001 From: Jamie Davis Date: Wed, 25 Apr 2018 20:03:48 -0400 Subject: [PATCH] security: rtrim, not unsafe /X+$/ idiom Problem: replace(/X+$/, '') is vulnerable to REDOS Solution: Replace all instances I could find with a custom rtrim --- lib/marked.js | 36 ++++++++++++++++++++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/lib/marked.js b/lib/marked.js index 83974865e4..50a6afa8a5 100644 --- a/lib/marked.js +++ b/lib/marked.js @@ -217,7 +217,7 @@ Lexer.prototype.token = function(src, top) { this.tokens.push({ type: 'code', text: !this.options.pedantic - ? cap.replace(/\n+$/, '') + ? rtrim(cap, '\n') : cap }); continue; @@ -1303,7 +1303,7 @@ function resolveUrl(base, href) { if (/^[^:]+:\/*[^/]*$/.test(base)) { baseUrls[' ' + base] = base + '/'; } else { - baseUrls[' ' + base] = base.replace(/[^/]*$/, ''); + baseUrls[' ' + base] = rtrim(base, '/', true); } } base = baseUrls[' ' + base]; @@ -1355,6 +1355,38 @@ function splitCells(tableRow, count) { return cells; } +// Return str with all trailing {c | all but c} removed +// allButC: Default false +function rtrim(str, c, allButC) { + if (typeof allButC === 'undefined') { + allButC = false; + } else { + allButC = true; + } + var mustMatchC = !allButC; + + if (str.length === 0) { + return ''; + } + + // ix+1 of leftmost that fits description + // i.e. the length of the string we should return + var curr = str.length; + + while (curr > 0) { + var currChar = str.charAt(curr - 1); + if (mustMatchC && currChar === c) { + curr--; + } else if (!mustMatchC && currChar !== c) { + curr--; + } else { + break; + } + } + + return str.substr(0, curr); +} + /** * Marked */