Skip to content

Commit 3492672

Browse files
authored
fix: improve limit option validation (#741)
* fix: improve limit option validation * chore: replace arrow functions in tests * ci: add Node.js 26 to ci matrix
1 parent 0defdbe commit 3492672

10 files changed

Lines changed: 158 additions & 13 deletions

File tree

.github/workflows/ci.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,9 @@ jobs:
147147
- name: Node.js 25.x
148148
node-version: "25"
149149

150+
- name: Node.js 26.x
151+
node-version: "26"
152+
150153
steps:
151154
- uses: actions/checkout@v4
152155

HISTORY.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
1+
unreleased
2+
===================
3+
* fix: improve `limit` option validation (#698)
4+
* Invalid `limit` values (e.g. unparseable strings or `NaN`) now throw instead of being silently ignored, which previously disabled size limit enforcement
5+
* `null` and `undefined` fall back to the default 100kb limit
6+
17
1.20.5 / 2026-04-24
28
===================
3-
* refactor(json): simplify strict mode error string construction
9+
* refactor(json): simplify strict mode error string construction
410
* fix: extended urlencoded parsing of arrays with >100 elements (#716)
511
* deps: qs@~6.15.1
612

lib/types/json.js

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,15 +53,19 @@ var JSON_SYNTAX_REGEXP = /#+/g
5353
function json (options) {
5454
var opts = options || {}
5555

56-
var limit = typeof opts.limit !== 'number'
57-
? bytes.parse(opts.limit || '100kb')
58-
: opts.limit
56+
var limit = typeof opts.limit === 'undefined' || opts.limit === null
57+
? 102400 // 100kb default
58+
: bytes.parse(opts.limit)
5959
var inflate = opts.inflate !== false
6060
var reviver = opts.reviver
6161
var strict = opts.strict !== false
6262
var type = opts.type || 'application/json'
6363
var verify = opts.verify || false
6464

65+
if (limit === null) {
66+
throw new TypeError('option limit "' + String(opts.limit) + '" is invalid')
67+
}
68+
6569
if (verify !== false && typeof verify !== 'function') {
6670
throw new TypeError('option verify must be function')
6771
}

lib/types/raw.js

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,12 +33,16 @@ function raw (options) {
3333
var opts = options || {}
3434

3535
var inflate = opts.inflate !== false
36-
var limit = typeof opts.limit !== 'number'
37-
? bytes.parse(opts.limit || '100kb')
38-
: opts.limit
36+
var limit = typeof opts.limit === 'undefined' || opts.limit === null
37+
? 102400 // 100kb default
38+
: bytes.parse(opts.limit)
3939
var type = opts.type || 'application/octet-stream'
4040
var verify = opts.verify || false
4141

42+
if (limit === null) {
43+
throw new TypeError('option limit "' + String(opts.limit) + '" is invalid')
44+
}
45+
4246
if (verify !== false && typeof verify !== 'function') {
4347
throw new TypeError('option verify must be function')
4448
}

lib/types/text.js

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,12 +35,16 @@ function text (options) {
3535

3636
var defaultCharset = opts.defaultCharset || 'utf-8'
3737
var inflate = opts.inflate !== false
38-
var limit = typeof opts.limit !== 'number'
39-
? bytes.parse(opts.limit || '100kb')
40-
: opts.limit
38+
var limit = typeof opts.limit === 'undefined' || opts.limit === null
39+
? 102400 // 100kb default
40+
: bytes.parse(opts.limit)
4141
var type = opts.type || 'text/plain'
4242
var verify = opts.verify || false
4343

44+
if (limit === null) {
45+
throw new TypeError('option limit "' + String(opts.limit) + '" is invalid')
46+
}
47+
4448
if (verify !== false && typeof verify !== 'function') {
4549
throw new TypeError('option verify must be function')
4650
}

lib/types/urlencoded.js

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,12 +50,16 @@ function urlencoded (options) {
5050

5151
var extended = opts.extended !== false
5252
var inflate = opts.inflate !== false
53-
var limit = typeof opts.limit !== 'number'
54-
? bytes.parse(opts.limit || '100kb')
55-
: opts.limit
53+
var limit = typeof opts.limit === 'undefined' || opts.limit === null
54+
? 102400 // 100kb default
55+
: bytes.parse(opts.limit)
5656
var type = opts.type || 'application/x-www-form-urlencoded'
5757
var verify = opts.verify || false
5858

59+
if (limit === null) {
60+
throw new TypeError('option limit "' + String(opts.limit) + '" is invalid')
61+
}
62+
5963
if (verify !== false && typeof verify !== 'function') {
6064
throw new TypeError('option verify must be function')
6165
}

test/json.js

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,36 @@ describe('bodyParser.json()', function () {
130130
})
131131

132132
describe('with limit option', function () {
133+
it('should throw an error for an invalid string limit', function () {
134+
assert.throws(function () {
135+
bodyParser.json({ limit: 'invalid' })
136+
}, /option limit "invalid" is invalid/)
137+
assert.throws(function () {
138+
bodyParser.json({ limit: '' })
139+
}, /option limit "" is invalid/)
140+
})
141+
142+
it('should throw an error for a NaN limit', function () {
143+
assert.throws(function () {
144+
bodyParser.json({ limit: NaN })
145+
}, /option limit "NaN" is invalid/)
146+
})
147+
148+
it('should throw an error for a boolean limit', function () {
149+
assert.throws(function () {
150+
bodyParser.json({ limit: true })
151+
}, /option limit "true" is invalid/)
152+
assert.throws(function () {
153+
bodyParser.json({ limit: false })
154+
}, /option limit "false" is invalid/)
155+
})
156+
157+
it('should throw an error for an object limit', function () {
158+
assert.throws(function () {
159+
bodyParser.json({ limit: { foo: 'bar' } })
160+
}, /option limit "\[object Object\]" is invalid/)
161+
})
162+
133163
it('should 413 when over limit with Content-Length', function (done) {
134164
var buf = Buffer.alloc(1024, '.')
135165
request(createServer({ limit: '1kb' }))

test/raw.js

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,36 @@ describe('bodyParser.raw()', function () {
8888
})
8989

9090
describe('with limit option', function () {
91+
it('should throw an error for an invalid string limit', function () {
92+
assert.throws(function () {
93+
bodyParser.raw({ limit: 'invalid' })
94+
}, /option limit "invalid" is invalid/)
95+
assert.throws(function () {
96+
bodyParser.raw({ limit: '' })
97+
}, /option limit "" is invalid/)
98+
})
99+
100+
it('should throw an error for a NaN limit', function () {
101+
assert.throws(function () {
102+
bodyParser.raw({ limit: NaN })
103+
}, /option limit "NaN" is invalid/)
104+
})
105+
106+
it('should throw an error for a boolean limit', function () {
107+
assert.throws(function () {
108+
bodyParser.raw({ limit: true })
109+
}, /option limit "true" is invalid/)
110+
assert.throws(function () {
111+
bodyParser.raw({ limit: false })
112+
}, /option limit "false" is invalid/)
113+
})
114+
115+
it('should throw an error for an object limit', function () {
116+
assert.throws(function () {
117+
bodyParser.raw({ limit: { foo: 'bar' } })
118+
}, /option limit "\[object Object\]" is invalid/)
119+
})
120+
91121
it('should 413 when over limit with Content-Length', function (done) {
92122
var buf = Buffer.alloc(1028, '.')
93123
var server = createServer({ limit: '1kb' })

test/text.js

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,36 @@ describe('bodyParser.text()', function () {
106106
})
107107

108108
describe('with limit option', function () {
109+
it('should throw an error for an invalid string limit', function () {
110+
assert.throws(function () {
111+
bodyParser.text({ limit: 'invalid' })
112+
}, /option limit "invalid" is invalid/)
113+
assert.throws(function () {
114+
bodyParser.text({ limit: '' })
115+
}, /option limit "" is invalid/)
116+
})
117+
118+
it('should throw an error for a NaN limit', function () {
119+
assert.throws(function () {
120+
bodyParser.text({ limit: NaN })
121+
}, /option limit "NaN" is invalid/)
122+
})
123+
124+
it('should throw an error for a boolean limit', function () {
125+
assert.throws(function () {
126+
bodyParser.text({ limit: true })
127+
}, /option limit "true" is invalid/)
128+
assert.throws(function () {
129+
bodyParser.text({ limit: false })
130+
}, /option limit "false" is invalid/)
131+
})
132+
133+
it('should throw an error for an object limit', function () {
134+
assert.throws(function () {
135+
bodyParser.text({ limit: { foo: 'bar' } })
136+
}, /option limit "\[object Object\]" is invalid/)
137+
})
138+
109139
it('should 413 when over limit with Content-Length', function (done) {
110140
var buf = Buffer.alloc(1028, '.')
111141
request(createServer({ limit: '1kb' }))

test/urlencoded.js

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -323,6 +323,36 @@ describe('bodyParser.urlencoded()', function () {
323323
})
324324

325325
describe('with limit option', function () {
326+
it('should throw an error for an invalid string limit', function () {
327+
assert.throws(function () {
328+
bodyParser.urlencoded({ limit: 'invalid' })
329+
}, /option limit "invalid" is invalid/)
330+
assert.throws(function () {
331+
bodyParser.urlencoded({ limit: '' })
332+
}, /option limit "" is invalid/)
333+
})
334+
335+
it('should throw an error for a NaN limit', function () {
336+
assert.throws(function () {
337+
bodyParser.urlencoded({ limit: NaN })
338+
}, /option limit "NaN" is invalid/)
339+
})
340+
341+
it('should throw an error for a boolean limit', function () {
342+
assert.throws(function () {
343+
bodyParser.urlencoded({ limit: true })
344+
}, /option limit "true" is invalid/)
345+
assert.throws(function () {
346+
bodyParser.urlencoded({ limit: false })
347+
}, /option limit "false" is invalid/)
348+
})
349+
350+
it('should throw an error for an object limit', function () {
351+
assert.throws(function () {
352+
bodyParser.urlencoded({ limit: { foo: 'bar' } })
353+
}, /option limit "\[object Object\]" is invalid/)
354+
})
355+
326356
it('should 413 when over limit with Content-Length', function (done) {
327357
var buf = Buffer.alloc(1024, '.')
328358
request(createServer({ limit: '1kb' }))

0 commit comments

Comments
 (0)