diff --git a/lib/core/request.js b/lib/core/request.js index 7271bc64f24..adb5bfcb3a8 100644 --- a/lib/core/request.js +++ b/lib/core/request.js @@ -304,6 +304,9 @@ function processHeader (request, key, val) { key.length === 4 && key.toLowerCase() === 'host' ) { + if (headerCharRegex.exec(val) !== null) { + throw new InvalidArgumentError(`invalid ${key} header`) + } // Consumed by Client request.host = val } else if ( diff --git a/test/headers-crlf.js b/test/headers-crlf.js new file mode 100644 index 00000000000..fa90eaadd11 --- /dev/null +++ b/test/headers-crlf.js @@ -0,0 +1,37 @@ +'use strict' + +const { test } = require('tap') +const { Client } = require('..') +const { createServer } = require('http') +const EE = require('events') + +test('CRLF Injection in Nodejs ‘undici’ via host', (t) => { + t.plan(1) + + const server = createServer(async (req, res) => { + res.end() + }) + t.teardown(server.close.bind(server)) + + server.listen(0, async () => { + const client = new Client(`http://localhost:${server.address().port}`) + t.teardown(client.close.bind(client)) + + const unsanitizedContentTypeInput = '12 \r\n\r\naaa:aaa' + + try { + const { body } = await client.request({ + path: '/', + method: 'POST', + headers: { + 'content-type': 'application/json', + 'host': unsanitizedContentTypeInput + }, + body: 'asd' + }) + await body.dump() + } catch (err) { + t.same(err.code, 'UND_ERR_INVALID_ARG') + } + }) +})