Skip to content

Commit 0cfe39e

Browse files
committed
security: replace unsafe /X+$/ idiom with rtrim
Problem: replace(/X+$/, '') is vulnerable to REDOS Solution: Replace all instances I could find with a custom rtrim
1 parent 943d995 commit 0cfe39e

File tree

1 file changed

+39
-11
lines changed

1 file changed

+39
-11
lines changed

lib/marked.js

Lines changed: 39 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,38 @@
44
* https://github.com/markedjs/marked
55
*/
66

7+
// Return str with all trailing {c | all but c} removed
8+
// allButC: Default false
9+
function rtrim(str, c, allButC) {
10+
if (typeof allButC === 'undefined') {
11+
allButC = false;
12+
} else {
13+
allButC = true;
14+
}
15+
var mustMatchC = !allButC;
16+
17+
if (str.length === 0) {
18+
return '';
19+
}
20+
21+
// ix+1 of leftmost that fits description
22+
// i.e. the length of the string we should return
23+
var curr = str.length;
24+
25+
while (curr > 0) {
26+
var currChar = str.charAt(curr - 1);
27+
if (mustMatchC && currChar === c) {
28+
curr--;
29+
} else if (!mustMatchC && currChar !== c) {
30+
curr--;
31+
} else {
32+
break;
33+
}
34+
}
35+
36+
return str.substr(0, curr);
37+
}
38+
739
;(function(root) {
840
'use strict';
941

@@ -216,7 +248,7 @@ Lexer.prototype.token = function(src, top) {
216248
this.tokens.push({
217249
type: 'code',
218250
text: !this.options.pedantic
219-
? cap.replace(/\n+$/, '')
251+
? rtrim(cap, '\n')
220252
: cap
221253
});
222254
continue;
@@ -238,15 +270,11 @@ Lexer.prototype.token = function(src, top) {
238270
src = src.substring(cap[0].length);
239271
// cap[2] might be ' HEADING # '
240272
item = (cap[2] || '').trim();
241-
if (item.slice(-1) === '#') {
242-
// NB replace(/#+$/) is quadratic on mismatch because it's unanchored,
243-
// so we protect with if-check to ensure it won't mismatch.
244-
if (this.options.pedantic) {
245-
item = item.replace(/#+$/, '');
246-
} else {
247-
// CM requires a space before additional #s
248-
item = item.replace(/(\s|^)#+$/, '');
249-
}
273+
if (this.options.pedantic) {
274+
item = rtrim(item, '#');
275+
} else {
276+
// CM requires a space before additional #s
277+
item = item.replace(/(\s|^)#+$/, '');
250278
}
251279
item = item.trim();
252280
this.tokens.push({
@@ -1288,7 +1316,7 @@ function resolveUrl(base, href) {
12881316
if (/^[^:]+:\/*[^/]*$/.test(base)) {
12891317
baseUrls[' ' + base] = base + '/';
12901318
} else {
1291-
baseUrls[' ' + base] = base.replace(/[^/]*$/, '');
1319+
baseUrls[' ' + base] = rtrim(base, '/', true);
12921320
}
12931321
}
12941322
base = baseUrls[' ' + base];

0 commit comments

Comments
 (0)