Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(cve): bump busboy to fix CVE-2022-24434 #1097

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 7 additions & 15 deletions lib/make-middleware.js
Original file line number Diff line number Diff line change
@@ -1,18 +1,13 @@
var is = require('type-is')
var Busboy = require('busboy')
var extend = require('xtend')
var onFinished = require('on-finished')
var appendField = require('append-field')

var Counter = require('./counter')
var MulterError = require('./multer-error')
var FileAppender = require('./file-appender')
var removeUploadedFiles = require('./remove-uploaded-files')

function drainStream (stream) {
stream.on('readable', stream.read.bind(stream))
}

function makeMiddleware (setup) {
return function multerMiddleware (req, res, next) {
if (!is(req, ['multipart'])) return next()
Expand All @@ -30,7 +25,7 @@ function makeMiddleware (setup) {
var busboy

try {
busboy = new Busboy({ headers: req.headers, limits: limits, preservePath: preservePath })
busboy = Busboy({ headers: req.headers, limits: limits, preservePath: preservePath })
} catch (err) {
return next(err)
}
Expand All @@ -45,12 +40,9 @@ function makeMiddleware (setup) {
function done (err) {
if (isDone) return
isDone = true

req.unpipe(busboy)
drainStream(req)
busboy.removeAllListeners()

onFinished(req, function () { next(err) })
next(err)
}

function indicateDone () {
Expand Down Expand Up @@ -80,9 +72,9 @@ function makeMiddleware (setup) {
}

// handle text field data
busboy.on('field', function (fieldname, value, fieldnameTruncated, valueTruncated) {
busboy.on('field', function (fieldname, value, { nameTruncated, valueTruncated }) {
if (fieldname == null) return abortWithCode('MISSING_FIELD_NAME')
if (fieldnameTruncated) return abortWithCode('LIMIT_FIELD_KEY')
if (nameTruncated) return abortWithCode('LIMIT_FIELD_KEY')
if (valueTruncated) return abortWithCode('LIMIT_FIELD_VALUE', fieldname)

// Work around bug in Busboy (https://github.com/mscdex/busboy/issues/6)
Expand All @@ -94,7 +86,7 @@ function makeMiddleware (setup) {
})

// handle files
busboy.on('file', function (fieldname, fileStream, filename, encoding, mimetype) {
busboy.on('file', function (fieldname, fileStream, { filename, encoding, mimeType }) {
// don't attach to the files object, if there is no file
if (!filename) return fileStream.resume()

Expand All @@ -107,7 +99,7 @@ function makeMiddleware (setup) {
fieldname: fieldname,
originalname: filename,
encoding: encoding,
mimetype: mimetype
mimetype: mimeType
}

var placeholder = appender.insertPlaceholder(file)
Expand Down Expand Up @@ -169,7 +161,7 @@ function makeMiddleware (setup) {
busboy.on('partsLimit', function () { abortWithCode('LIMIT_PART_COUNT') })
busboy.on('filesLimit', function () { abortWithCode('LIMIT_FILE_COUNT') })
busboy.on('fieldsLimit', function () { abortWithCode('LIMIT_FIELD_COUNT') })
busboy.on('finish', function () {
busboy.on('close', function () {
readFinished = true
indicateDone()
})
Expand Down
5 changes: 2 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,10 @@
],
"dependencies": {
"append-field": "^1.0.0",
"busboy": "^0.2.11",
"busboy": "^1.0.0",
"concat-stream": "^1.5.2",
"mkdirp": "^0.5.4",
"object-assign": "^4.1.1",
"on-finished": "^2.3.0",
"type-is": "^1.6.4",
"xtend": "^4.0.0"
},
Expand All @@ -39,7 +38,7 @@
"testdata-w3c-json-form": "^1.0.0"
},
"engines": {
"node": ">= 0.10.0"
"node": ">= 6.0.0"
},
"files": [
"LICENSE",
Expand Down
8 changes: 1 addition & 7 deletions test/_util.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
var fs = require('fs')
var path = require('path')
var stream = require('stream')
var onFinished = require('on-finished')

exports.file = function file (name) {
return fs.createReadStream(path.join(__dirname, 'files', name))
Expand All @@ -17,19 +16,14 @@ exports.submitForm = function submitForm (multer, form, cb) {

var req = new stream.PassThrough()

req.complete = false
form.once('end', function () {
req.complete = true
})

form.pipe(req)
req.headers = {
'content-type': 'multipart/form-data; boundary=' + form.getBoundary(),
'content-length': length
}

multer(req, null, function (err) {
onFinished(req, function () { cb(err, req) })
cb(err, req)
})
})
}
2 changes: 1 addition & 1 deletion test/error-handling.js
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,7 @@ describe('Error Handling', function () {
req.end(body)

upload(req, null, function (err) {
assert.strictEqual(err.message, 'Unexpected end of multipart data')
assert.strictEqual(err.message, 'Unexpected end of form')
done()
})
})
Expand Down
3 changes: 1 addition & 2 deletions test/express-integration.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ var util = require('./_util')
var express = require('express')
var FormData = require('form-data')
var concat = require('concat-stream')
var onFinished = require('on-finished')

var port = 34279

Expand All @@ -27,7 +26,7 @@ describe('Express Integration', function () {
req.on('response', function (res) {
res.on('error', cb)
res.pipe(concat({ encoding: 'buffer' }, function (body) {
onFinished(req, function () { cb(null, res, body) })
cb(null, res, body)
}))
})
}
Expand Down
36 changes: 21 additions & 15 deletions test/unicode.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,10 @@

var assert = require('assert')

var path = require('path')
var util = require('./_util')
var multer = require('../')
var temp = require('fs-temp')
var rimraf = require('rimraf')
var FormData = require('form-data')
var stream = require('stream')

describe('Unicode', function () {
var uploadDir, upload
Expand All @@ -34,21 +32,29 @@ describe('Unicode', function () {
})

it('should handle unicode filenames', function (done) {
var form = new FormData()
var parser = upload.single('small0')
var filename = '\ud83d\udca9.dat'

form.append('small0', util.file('small0.dat'), { filename: filename })

util.submitForm(parser, form, function (err, req) {
var req = new stream.PassThrough()
var boundary = 'AaB03x'
var body = [
'--' + boundary,
'Content-Disposition: form-data; name="small0"; filename="poo.dat"; filename*=utf-8\'\'%F0%9F%92%A9.dat',
'Content-Type: text/plain',
'',
'test with unicode filename',
'--' + boundary + '--'
].join('\r\n')

req.headers = {
'content-type': 'multipart/form-data; boundary=' + boundary,
'content-length': body.length
}

req.end(body)

upload.single('small0')(req, null, function (err) {
assert.ifError(err)

assert.strictEqual(path.basename(req.file.path), filename)
assert.strictEqual(req.file.originalname, filename)

assert.strictEqual(req.file.originalname, '\ud83d\udca9.dat')
assert.strictEqual(req.file.fieldname, 'small0')
assert.strictEqual(req.file.size, 1778)
assert.strictEqual(util.fileSize(req.file.path), 1778)

done()
})
Expand Down