diff --git a/API.md b/API.md
index 4109be326..ff749d6c0 100755
--- a/API.md
+++ b/API.md
@@ -3048,6 +3048,12 @@ Default value: `1048576` (1MB).
Limits the size of incoming payloads to the specified byte count. Allowing very large payloads may
cause the server to run out of memory.
+#### `route.options.payload.maxParts`
+
+Default value: `1000`.
+
+Limits the number of parts allowed in multipart payloads.
+
#### `route.options.payload.multipart`
Default value: `false`.
diff --git a/lib/config.js b/lib/config.js
index e3768aecf..2b668f97d 100755
--- a/lib/config.js
+++ b/lib/config.js
@@ -153,6 +153,7 @@ internals.routeBase = Validate.object({
override: Validate.string(),
protoAction: Validate.valid('error', 'remove', 'ignore').default('error'),
maxBytes: Validate.number().integer().positive().default(1024 * 1024),
+ maxParts: Validate.number().integer().positive().default(1000),
uploads: Validate.string().default(Os.tmpdir()),
failAction: internals.failAction,
timeout: Validate.number().integer().positive().allow(false).default(10 * 1000),
diff --git a/package.json b/package.json
index aa5d1d32b..33f2e56bb 100755
--- a/package.json
+++ b/package.json
@@ -38,7 +38,7 @@
"@hapi/shot": "^6.0.1",
"@hapi/somever": "^4.1.1",
"@hapi/statehood": "^8.0.1",
- "@hapi/subtext": "^8.0.1",
+ "@hapi/subtext": "^8.1.0",
"@hapi/teamwork": "^6.0.0",
"@hapi/topo": "^6.0.1",
"@hapi/validate": "^2.0.1"
diff --git a/test/payload.js b/test/payload.js
index c13b9aafd..be049ac28 100755
--- a/test/payload.js
+++ b/test/payload.js
@@ -686,6 +686,19 @@ describe('Payload', () => {
expect(res.result.pics).to.exist();
});
+ it('places default limit on max parts in multipart payloads', async () => {
+
+ const part = '--AaB03x\r\n' + 'content-disposition: form-data; name="x"\r\n\r\n' + 'x\r\n';
+ const multipartPayload = part.repeat(1001) + '--AaB03x--\r\n';
+
+ const server = Hapi.server({ routes: { payload: { multipart: true } } });
+ server.route({ method: 'POST', path: '/', handler: () => null });
+
+ const res = await server.inject({ method: 'POST', url: '/', payload: multipartPayload, headers: { 'content-type': 'multipart/form-data; boundary=AaB03x' } });
+ expect(res.statusCode).to.equal(400);
+ expect(res.result.message).to.equal('Invalid multipart payload format');
+ });
+
it('signals connection close when payload is unconsumed', async () => {
const payload = Buffer.alloc(1024);