Skip to content

Commit 6944abf

Browse files
committed
Handle extremely long and terrible patterns more gracefully
Reported by @nstarke, thanks
1 parent 8ac560e commit 6944abf

File tree

2 files changed

+43
-3
lines changed

2 files changed

+43
-3
lines changed

minimatch.js

+15-3
Original file line numberDiff line numberDiff line change
@@ -235,7 +235,7 @@ function braceExpand (pattern, options) {
235235
? this.pattern : pattern
236236

237237
if (typeof pattern === 'undefined') {
238-
throw new Error('undefined pattern')
238+
throw new TypeError('undefined pattern')
239239
}
240240

241241
if (options.nobrace ||
@@ -261,6 +261,10 @@ function braceExpand (pattern, options) {
261261
Minimatch.prototype.parse = parse
262262
var SUBPARSE = {}
263263
function parse (pattern, isSub) {
264+
if (pattern.length > 1024 * 64) {
265+
throw new TypeError('pattern is too long')
266+
}
267+
264268
var options = this.options
265269

266270
// shortcuts
@@ -518,7 +522,7 @@ function parse (pattern, isSub) {
518522
for (pl = patternListStack.pop(); pl; pl = patternListStack.pop()) {
519523
var tail = re.slice(pl.reStart + 3)
520524
// maybe some even number of \, then maybe 1 \, followed by a |
521-
tail = tail.replace(/((?:\\{2})*)(\\?)\|/g, function (_, $1, $2) {
525+
tail = tail.replace(/((?:\\{2}){0,64})(\\?)\|/g, function (_, $1, $2) {
522526
if (!$2) {
523527
// the | isn't already escaped, so escape it.
524528
$2 = '\\'
@@ -615,7 +619,15 @@ function parse (pattern, isSub) {
615619
}
616620

617621
var flags = options.nocase ? 'i' : ''
618-
var regExp = new RegExp('^' + re + '$', flags)
622+
try {
623+
var regExp = new RegExp('^' + re + '$', flags)
624+
} catch (er) {
625+
// If it was an invalid regular expression, then it can't match
626+
// anything. This trick looks for a character after the end of
627+
// the string, which is of course impossible, except in multi-line
628+
// mode, but it's not a /m regex.
629+
return new RegExp('$.')
630+
}
619631

620632
regExp._glob = pattern
621633
regExp._src = re

test/redos.js

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
var t = require('tap')
2+
3+
var minimatch = require('../')
4+
5+
// utility function for generating long strings
6+
var genstr = function (len, chr) {
7+
var result = ''
8+
for (var i = 0; i <= len; i++) {
9+
result = result + chr
10+
}
11+
12+
return result
13+
}
14+
15+
var exploit = '!(' + genstr(1024 * 15, '\\') + 'A)'
16+
17+
// within the limits, and valid match
18+
t.ok(minimatch('A', exploit))
19+
20+
// within the limits, but results in an invalid regexp
21+
exploit = '[!(' + genstr(1024 * 15, '\\') + 'A'
22+
t.notOk(minimatch('A', exploit))
23+
24+
t.throws(function () {
25+
// too long, throws TypeError
26+
exploit = '!(' + genstr(1024 * 64, '\\') + 'A)'
27+
minimatch('A', exploit)
28+
}, TypeError)

0 commit comments

Comments
 (0)